In this exercise, we will pull together many aspects of what we have learned so far to calibrate the HBV model to weighted data from the Fraser Experimental Forest in Colorado using precipitation/runoff and potential evapotranspiration (PET) data derived from the methods explored in the snowmelt and evapotranspiration modules.

HBV is: In the previous labs, we have worked with single-process models. HBV is more complex process-based model using many parameters to describe the physical processes of the hydrologic cycle https://rpubs.com/sdhakal/848236

From: Durga Lal Shrestha & Dimitri P. Solomatine (2008) Data‐driven approaches for estimating uncertainty in rainfall‐runoff modelling, International Journal of River Basin Management, 6:2, 109-122, DOI: 10.1080/15715124.2008.9635341

HBV versions with a GUI exists, but the data manipulation is more convenient in a coding environment, and we want you to be able to see ‘under the hood’. Instead of dealing with the inner workings of the model too much, we will put the focus on importing and organizing the data, getting the model running, manual optimization.

The HBV realization we will be using is contained in the R package TUWmodel. Please search that package in your browser and familiarize yourself with it (that will be the first step). TUW simply means “Technische Universitaet Wien”, or Vienna University of Technology. The model is slightly different from the original HBV but still similar enough to call it HBV. We also need to understand the arguments and parameters required for the model.

Type ‘?TUWmodel’ in your console. The package comes with an example dataset, and you can run examples either by copying and pasting the data(), TUWmodel() and plots into your console, or you can find and click ‘Run examples’ under the Examples header and view the script and plot outputs in the Help window. The first example shows how the ‘TUWmodel’ can be run given specifications for a long set of parameters (param). You can provide the model with precip, air temperature, area and ET along with the parameter set and it will simulate SWE, snowmelt and discharge. We can obtain measurements for each of these variables, so we will import all of this data and test the fit of the simulated data.

https://cran.r-project.org/web/packages/TUWmodel/TUWmodel.pdf

Import data:

We will generate a conceptual runoff model starting with:
- RainMeltWeighted_mm –> liquid input to the ground, combination of rain and melt
- PWeighted_mm –> Precipitation measured at the SNOTEL sites, both liquid and frozen. This is NOT water that went into the ground at that point. This is, however, the P input time series for the HBV model.
- SweWeighted_mm –> Snow water equivalent at the SNOTEL sites. We can use this to evaluate our snow routine.
- TempWeighted –> Either daily mean, min, or max. We will use the mean. - Discharge_mm –> Q observed at the outlet.
- ET –> Potential Evapotranspiration calculated using relative humidity and temperature.

Labwork (20 pnts)

Our first steps will be to import and format the data. As you might recall from the previous modules, this step can require the most script and ‘work’, but is critical to a valid model output. In this assignment, we have simplified much of the data collection for you, as the steps are ones you have already completed in previous modules. In the .csv imported below, we started by collecting the same SNOTEL data that you used in the snowmelt module, but downloaded for a greater date range (water years 2018-2022) (date, SWE depth in mm, and daily precipitation (mm)) However, you will notice that the column names of the provided table contain ‘weighted_’.

# Import data
indata <- read.csv("HBV_data/weighted_data_fool_HBV.csv")%>%
  mutate(date = ymd(date)) %>%
  rename(Q_m3_s = m3_s, Q_mm_day = mm_day, runoff_input.mm = input.mm )

str(indata)
'data.frame':   1826 obs. of  17 variables:
 $ date              : Date, format: "2017-10-01" ...
 $ wtr_yr            : int  2018 2018 2018 2018 2018 2018 2018 2018 2018 2018 ...
 $ weighted_swe.mm   : num  13.3 46.7 53.4 53.4 51.2 ...
 $ weighted_precip.mm: num  26.78 7.65 1.91 0 0 ...
 $ weighted_pcumul.mm: num  26.8 34.4 36.3 36.3 36.3 ...
 $ Q_m3_s            : num  0.00862 0.00743 0.00715 0.00704 0.00704 ...
 $ Q_mm_day          : num  0.282 0.243 0.234 0.23 0.231 ...
 $ Tmax_c            : num  5.55 1.95 5.25 12.75 12.75 ...
 $ Tmean_c           : num  0.8 -1.6 -0.7 6.2 6.65 0.25 3.2 2.5 -7.8 -1.8 ...
 $ Tmin_c            : num  -3.95 -5.15 -6.65 -0.35 0.55 ...
 $ RHmin             : num  43.1 60.3 41.2 28.9 27.4 ...
 $ RHmax             : num  90.6 91.8 91.2 86 78.6 ...
 $ month             : int  10 10 10 10 10 10 10 10 10 10 ...
 $ day               : int  1 2 3 4 5 6 7 8 9 10 ...
 $ SWEdiff.mm        : num  0 33.38 6.75 0 -2.28 ...
 $ Pdiff.mm          : num  0 7.65 1.91 0 0 ...
 $ runoff_input.mm   : num  0 0 0 0 2.28 ...

As we noted in the Snowmelt module, factors such as elevation and vegetation will affect the of snow-to-runoff rate. Similarly, temperature and precipitation differ with elevation, meaning that SNOTEL data from a single location may not fully represent conditions across the entire watershed.

To account for these variations, the “weighted” values for this exercise have been adjusted using linear scaling relationships that estimate average conditions across the watershed. The adjustments use elevation-precipitation and elevation-temperature relationships derived from inverse distance weighting to better approximate spatially distributed hydrological inputs rather than relying on a single point measurement.

If you are interested, you can start exploring spatial interpolation with: 1. Thiessen polygons Thiessen polygons 2. Inverse distance weighting 3. Kringing methods to determine if any of these are applicable to your study area.

Other columns in this data include: Q_m3_s and Q_mm_day - Discharge (Q) collected at the Fool Creek outlet by USFS, in units of cubic meters per second and mm per day from April until October. Tmax_c, Tmin_c and Tmean_c - Typically, we could find daily mean, max and minimum temperatures in the SNOTEL datasets, however, this particular station is missing temperature data (due to restrictions on technical access in 2020), so we retrieved temperature data from GridMET through Climate Engine. This highlights the importance of evaluating each variable for completeness. It will save you the headache of running the entire workflow, only to find that model outputs cannot be simulated for the later half of 2020 due to missing input data. RHmin, RHmax - Relative humidity daily min and max, also from GridMET, accessed through Climate Engine SWEdiff.mm, Pdiff.mm and runoff_input.mm - all daily outputs of a temperature based snowmelt model (the same as in the snowmelt module). runoff_input is the estimated daily input to the stream from melted snow and liquid precipitation combined.

Keep in mind that you can plot more than two variables in a single plot, but they will be most helpful if you group variables with a similar y-scale. For example, cumulative precipitation or SWE values will have a different range than variables that represent daily measurements like ‘input_mm’. Alternatively, you can add a secondary y-axis to your plot.

ggplot(data = indata) +
  geom_point(aes(x = date, y = runoff_input.mm, color = "runoff_input.mm"), size = 0.5) +  # Assign a label for legend
  geom_point(aes(x = date, y = Q_mm_day, color = "mm/day"), size = 0.5) +  # Assign a different label
  geom_point(aes(x = date, y = weighted_precip.mm, color = "weighted_precip.mm"), size = 0.5) +  # Assign a different label
  geom_point(aes(x = date, y = Pdiff.mm, color = "Pdiff.mm"), size = 0.5) +
  scale_color_manual(values = c("runoff_input.mm" = "blue", "mm/day" = "red", "weighted_precip.mm" = "green", "Pdiff.mm" = 'purple')) +  # Customize colors
  labs(color = "Discharge Units") +  # Legend title
  theme_minimal()

2,930m. watershed_area_m2 <- 2640000

Note that while the stream is snow-covered, there are no stage/flow measurements being made at this site. For many of our calculations to work, we will not want NA in our data frames. In this data set, if we view the tabular data, the end discharge reading (Q_mm_day), is very similar to the first in the following calendar year. For this example, we will then fill the NA values with the mean of the final and first readings for each winter (Oct - April) NA string.

# Rather than scrolling through a dataframe, this gives us a sum of 'NA' ros in this column
sum(is.na(indata$Q_mm_day))
[1] 917
# Function to fill NA values in Q_mm_day during winter (Oct - Apr)
fill_na_winter <- function(df) {
  df <- df %>%
    arrange(date) %>% # Ensure data is sorted
    mutate(
      month = month(date),
      is_winter = month %in% c(10, 11, 12, 1, 2, 3, 4) # Identify winter months
    )
  
  # Identify NA stretches in winter months
  na_indices <- which(is.na(df$Q_mm_day) & df$is_winter)
  
  for (idx in na_indices) {
    # Find the last non-NA before the current NA
    prev_value <- df$Q_mm_day[max(which(!is.na(df$Q_mm_day[1:(idx - 1)])))]
    
    # Find the next non-NA after the current NA
    next_value <- df$Q_mm_day[min(which(!is.na(df$Q_mm_day[(idx + 1):nrow(df)])) + idx)]
    
    # Replace the NA with the average of prev_value and next_value
    if (!is.na(prev_value) & !is.na(next_value)) {
      df$Q_mm_day[idx] <- (prev_value + next_value) / 2
    }
  }
  
  return(df)
}

# Apply the function
indata <- fill_na_winter(indata)

Let’s try our quick check again:

# Now we should see zero NA in this column
sum(is.na(indata$Q_mm_day))
[1] 0

Next, we need to add daily potential evapotranspiration (PET) to the dataset. The evapotranspiration module covered some of the numerous pre-built functions available in various R packages designed for ET estimation. For instance, the ‘Evapotranspiration’ package provides ET estimates derived from approximately 20 distinct equations or variations. These functions require precise data formatting to ensure compatibility with the function arguments. To help you structure your function inputs similarly, many packages come with example datasets in their documentation. SPEI is another package that offers ET functions. The github repository for this package has been updated fairly recently, which can be important to verify.

We chose to write our own function here so you could ‘see under the hood’.
Not all packages are equally maintained, as they are often developed by researchers or modelers to improve the repeatably of their work, and contribute to the broader scientific community. Once funding ceases, or if the original developer moves on to new projects, a custom package may no longer receive updates or support. As R, RStudio and other supporting packages are updated, a package may become depreciated. If the package still functions correctly in your current R version and dependencies, there’s no immediate reason to stop using it. However, if you are concerned that future versions of R or dependencies might break the packages you use, you can check the development and maintenance history of custom or specialized packages (or write a package or function for yourself as exemplified below!).

Here is our Hargreaves function, adapted from the ‘Evapotranspiration’ package to minimize re-formatting of our dataframe.


# Function to calculate ET
calculate_ET <- function(data, constants, ts = "daily", message = "yes", save.csv = "no", ...) {
  
  # Check for required data
  if (is.null(data$Tmax) | is.null(data$Tmin)) {
    stop("Required data missing for 'Tmax' and 'Tmin', or 'Temp'")
  }
  
  # Hargreaves-Samani ET Calculation
  Ta <- (data$Tmax + data$Tmin) / 2
  P <- 101.3 * ((293 - 0.0065 * constants$Elev) / 293) ^ 5.26
  delta <- 4098 * (0.6108 * exp((17.27 * Ta) / (Ta + 237.3))) / ((Ta + 237.3) ^ 2)
  gamma <- 0.00163 * P / constants$lambda
  d_r2 <- 1 + 0.033 * cos(2 * pi / 365 * data$J)
  delta2 <- 0.409 * sin(2 * pi / 365 * data$J - 1.39)
  w_s <- acos(-tan(constants$lat_rad) * tan(delta2))
  N <- 24 / pi * w_s
  R_a <- (1440 / pi) * d_r2 * constants$Gsc * (w_s * sin(constants$lat_rad) * sin(delta2) + 
                                               cos(constants$lat_rad) * cos(delta2) * sin(w_s))
  C_HS <- 0.00185 * (data$Tmax - data$Tmin) ^ 2 - 0.0433 * (data$Tmax - data$Tmin) + 0.4023
  ET_HS.Daily <- 0.0135 * C_HS * R_a / constants$lambda * (data$Tmax - 
                                                              data$Tmin) ^ 0.5 * (Ta + 17.8)
  ET.Daily <- ET_HS.Daily
  
  # Create YearMonth Column
  data$YearMonth <- as.Date(paste(year(data$Date.daily), month(data$Date.daily), "01", sep = "-"))
  
  # Annual and Monthly Aggregations
  ET.Annual <- aggregate(ET.Daily ~ year(YearMonth), data = data, FUN = sum)
  ET.Monthly <- aggregate(ET.Daily ~ YearMonth, data = data, FUN = sum)
  
  # ET formulating
  ET_formulation <- "Hargreaves-Samani"
  ET_type <- "Reference Crop ET"
  results <- list(ET.Daily = ET.Daily, ET.Monthly = ET.Monthly, 
                  ET.Annual = ET.Annual, ET_formulation = ET_formulation, 
                  ET_type = ET_type)
  
  # Save to CSV if required
  if (save.csv == "yes") {
    for (i in 1:length(results)) {
      namer <- names(results[i])
      write.table(as.character(namer), file = "ET_HargreavesSamani.csv", 
                  dec = ".", quote = FALSE, col.names = FALSE, 
                  row.names = F, append = TRUE, sep = ",")
      write.table(data.frame(get(namer, results)), file = "ET_HargreavesSamani.csv", 
                  col.names = F, append = TRUE, sep = ",")
    }
    invisible(results)
  } else {
    return(results)
  }
}

Now we will format the inputs so the data is easily read by the function, and run the function.

# Format our data to fit the function
PET_data <- list(
  Tmax = indata$Tmax,
  Tmin = indata$Tmin,
  J = as.numeric(format(indata$date, "%j")),
  Date.daily = indata$date
)

# Define constants
constants <- list(
  Elev = 2900,                            # Elevation in meters
  lambda = 2.45,                          # Latent heat of vaporization in MJ.kg^-1
  lat_rad = 39.88 * pi / 180,             # Latitude in radians
  Gsc = 0.0820                            # Solar constant in MJ.m^-2.min^-1
)

PET_Hargreaves <- calculate_ET(
  data = PET_data,
  constants = constants,
  ts = "daily",        # Optional; defaults to "daily"
  message = "yes",     # Optional; prints summary 
  save.csv = "no"      # Optional; do not save results to a CSV
)

Now we’ll add daily ET into our original dataframe:

PET_mm <- PET_Hargreaves$ET.Daily
# put the approximated PET_mm into the larger indata df
indata <- cbind(indata, PET_mm)  #with cbind

head(indata)
# Annual summary stats
indata_analysis <- indata %>%
  select(-date) %>%
  group_by(wtr_yr) %>%
  summarise(
    weighted_precip.mm = sum(weighted_precip.mm, na.rm = TRUE),
    Tmean_c = mean(Tmean_c, na.rm = TRUE),
    swe.mm_max = max(weighted_swe.mm, na.rm = TRUE),
    pcumul.mm_max = max(weighted_pcumul.mm, na.rm = TRUE),
    Tmax = max(Tmax_c, na.rm = TRUE),
    Tmin = min(Tmin_c, na.rm = TRUE),
    Q_mm_sum = sum(Q_mm_day, na.rm = TRUE),
    PET_mm_sum = sum(PET_mm, na.rm = TRUE), 
    runoff_input.mm = sum(runoff_input.mm, na.rm = TRUE),
  )

indata_analysis
NA
# Your script below should fit your variables from your summary dataframe above. Here is an example of what a simple water balance might look like if I named my summary dataframe indata_analysis: 

# Calculate the residual water after accounting for PET and discharge
residual_water <- indata_analysis$runoff_input.mm - (indata_analysis$PET_mm_sum + indata_analysis$Q_mm_sum)

# View the residual for each year
print(residual_water)
[1] -245.4585632    0.5648919 -184.4922861 -231.7575558 -219.0837730

By subtracting discharge and PET from runoff_input, we’re essentially examining the residual water. This could represent the amount of water available to the system after accounting for the demand (PET) and the outflow (discharge).

# make long form with PETsum and Psum as the key-value pairs (exclude wtr_yr from )
dat_sum_plot <- indata_analysis %>%
  pivot_longer(names_to =  "key", values_to =  "value", -wtr_yr)

# bar plot pf PET and P for each year
ggplot(dat_sum_plot, aes(x = wtr_yr, y = value, fill = key)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(x = "Water Year", y = "mm/year", fill = {})

### TIMING
# create weekly means or totals for both time series and plot them together to determine the timing of each 
dat_weekly <- indata %>%
  group_by(Week = week(date)) %>%
  summarise(
    PET = sum(PET_mm), 
    P = sum(runoff_input.mm)
    ) %>%
    pivot_longer(names_to = "key", values_to = "value", -Week)

# line plot of P and PET on a weekly basis. Use dat_weekly as the data source.
ggplot(dat_weekly, aes(x = Week, y = value, color = key)) +
  geom_line() + # create line plot
  labs(x = "Week of Year", y = "mm/year", color = {})

Single model run

Look at the parameters to make sure you know what each parameter does. The way the model is set up, is that everything is hidden inside a function. The user (–> you) only formats the input data and passes the parameters to the function. All model output is contained in “modelRun”. If you look at the Environment, you will notice that modelRun is a list. A list is even more flexible in terms of data storage than a dataframe (a dataframe is actually a special type of list…). While lists are super flexible, they can also be more cumbersome to deal with. I included some code that takes the output from the model run and saves all the important bits and pieces in a convenient dataframe called HBVRun. For this part (single model runs), you will really only need the data contained in the HBVRun dataframe.

single model execution

# set up the parameter vector
model_params <- c(
  1.05, # SCF snow correction factor [-] (e.g., 0.9-1.5);
  1.80, # DDF degree day factor [mm/degC/timestep] (e.g., 0.0-5.0 mm/degC/day);
  2, # Tr threshold temperature above which precipitation is rain [degC] (e.g., 1.0-3.0 degC);
  0, # Ts threshold temperature below which precipitation is snow [degC] (e.g., -3.0-1.0 degC);
  -0.336, # Tm threshold temperature above which melt starts [degC] (e.g., -2.0-2.0 degC);
  0.2, # LPrat parameter related to the limit for potential evaporation [-] (e.g., 0.0-1.0);
  121, # FC field capacity, i.e., max soil moisture storage [mm] (e.g., 0-600 mm);
  2.52, # BETA the non linear parameter for runoff production [-] (e.g., 0.0-20.0);
  0.473, # k0 storage coefficient for very fast response [timestep] (e.g., 0.0-2.0 days);
  9.06, # k1 storage coefficient for fast response [timestep] (e.g., 2.0-30.0 days);
  142, # k2 storage coefficient for slow response [timestep] (e.g., 30.0-250.0 days);
  50.1, # lsuz threshold storage state, i.e., the very fast response start if exceeded [mm] (e.g., 1.0-100.0 mm);
  2.38, # cperc constant percolation rate [mm/timestep] (e.g., 0.0-8.0 mm/day);
  10, # bmax maximum base at low flows [timestep] (e.g., 0.0-30.0 days);
  25 # croute free scaling parameter [timestep^2/mm] (e.g., 0.0-50.0 days^2/mm);
)


# set time period
model_in <- indata %>%
  filter(date >= as_date("2017-10-01") & date <= as_date("2022-09-30"))

# set up the model
## THIS IS THE ACTUAL MODEL EXECUTION
modelRun <- TUWmodel(
  prec = model_in$weighted_precip.mm, # precip input
  airt = model_in$Tmean_c, # air temp input
  ep = model_in$PET_mm, # pet input
  area = 1, # one zone for the entire watershed
  param = model_params # input model parameters
)


# get all outputs into a nice df
HBVRun <- tibble(
  Date = model_in$Date, # date
  P_mm = modelRun$prec, # precip
  Tair = modelRun$airt, # air temp
  SWEobs = model_in$weighted_swe.mm, # observed swe
  PET = modelRun$ep,# pet
  Qobs = model_in$Q_mm_day, # observed discharge
  Qsim = modelRun$q[1, ], # simulated discharge
  Qsurf = modelRun$q0[1, ], # surface runoff
  Qsubsurf = modelRun$q1[1, ], # subsurface flow
  Qbase = modelRun$q2[1, ], # groundwater flow
  Rain = modelRun$rain[1, ], # simulated rain
  Snow = modelRun$snow[1, ], # simulated snowfall
  Melt = modelRun$melt[1, ], # simulated melt
  SWEsim = modelRun$swe[1, ], # simulated swe
  Soilmoist = modelRun$moist[1, ], # simulated soil storage
  AET = modelRun$eta[1, ], # simulated evapotranspiration
  StorageUpper = modelRun$suz[1, ], # upper storage value
  StorageLower = modelRun$slz[1, ] # lower storage value
)

Objective functions

KGE

Before we can start trying to tune our model to look more like the observed discharge record, it would be helpful to have some sort of quantified metric for how well our modeled data fits the measured data.

There are many different ways to do this, but discussion of the pros and cons of those approaches is beyond this quick introduction to modeling.

Here we will demonstrate the Kling-Gupta efficiency both for runoff as well as for swe.

# select the Qobs and Qsim timeseries
# DON'T FORGET TO EXCLUDE THE FIRST YEAR
Qobs <- HBVRun$Qobs[366:length(HBVRun$Qobs)] # observed runoff WITHOUT WARM-UP PERIOD
Qsim <- HBVRun$Qsim[366:length(HBVRun$Qsim)] # simulated runoff WITHOUT WARM-UP PERIOD

# KGE
kge_r_q <- cor(Qobs, Qsim)
kge_beta_q <- mean(Qsim) / mean(Qobs)
kge_gamma_q <- (sd(Qsim) / mean(Qsim)) / (sd(Qobs) / mean(Qobs))
kge_q <- 1 - sqrt((kge_r_q - 1)^2 + (kge_beta_q - 1)^2 + (kge_gamma_q - 1)^2)
kge_q
[1] 0.4775681
## Snow - water equivalent
SWEobs <- HBVRun$SWEobs[366:length(HBVRun$SWEobs)] # observed swe WITHOUT WARM-UP PERIOD
SWEsim <- HBVRun$SWEsim[366:length(HBVRun$SWEobs)] # simulated swe WITHOUT WARM-UP PERIOD

# KGE
kge_r_swe <- cor(SWEobs, SWEsim)
kge_beta_swe <- mean(SWEsim) / mean(SWEobs)
kge_gamma_swe <- (sd(SWEsim) / mean(SWEsim)) / (sd(SWEobs) / mean(SWEobs))
kge_swe <- 1 - sqrt((kge_r_swe - 1)^2 + (kge_beta_swe - 1)^2 + (kge_gamma_swe - 1)^2)
kge_swe
[1] 0.563363

NSE

Nash-Sutcliffe Efficiency (NSE).

Basically, the NSE looks at how much better your model run did that if you had just used the mean discharge for the data record as your “modelled results”. It does this by comparing how far off the observed values where from the mean discharge to how far off the modeled values were from the observed discharge.

Mathematically, NSE is the sum of the squared differences between the modeled and observed discharge divided by the sum of the squared differences between the observed and mean discharge, subtracted by 1.

\[ NSE = 1 - \frac{\sum_{t = 1}^{T}{(Q_m^t - Q_o^t)^2}}{\sum_{t = 1}^{T}{(Q_o^t - \bar{Q_o})^2}} \] Where \(Q_m^t\) is modeled discharge at time t, \(Q_o^t\) is observed discharge at time t, and \(\bar{Q_o}\) is mean observed discharge.

#Calculate NSE for snow, SWE is modeled, STA2 is measured
NSE_Q <- 1 - ((sum((HBVRun$Qobs - HBVRun$Qsim) ^ 2)) / 
                 sum((HBVRun$Qsim - mean(HBVRun$Qsim)) ^ 2))

NSE_Q
[1] 0.1264142
#Calculate NSE for snow, SWE is modeled, STA2 is measured
NSEsno <- 1 - ((sum((HBVRun$SWEobs - HBVRun$SWEsim) ^ 2)) / 
                 sum((HBVRun$SWEsim - mean(HBVRun$SWEsim)) ^ 2))

NSEsno
[1] -0.1020562

Calibrate HBV manually

Woohoo! We can now run our model and assess how well it is working!

Now, let’s see how well we can get it to work. The code below runs the model, produces a plot, and calculates the NSE based on discharge.


# set up the parameter vector
model_params <- c(
  1.05, # SCF snow correction factor [-] (e.g., 0.9-1.5);
  1.80, # DDF degree day factor [mm/degC/timestep] (e.g., 0.0-5.0 mm/degC/day);
  2, # Tr threshold temperature above which precipitation is rain [degC] (e.g., 1.0-3.0 degC);
  0, # Ts threshold temperature below which precipitation is snow [degC] (e.g., -3.0-1.0 degC);
  -0.336, # Tm threshold temperature above which melt starts [degC] (e.g., -2.0-2.0 degC);
  0.2, # LPrat parameter related to the limit for potential evaporation [-] (e.g., 0.0-1.0);
  121, # FC field capacity, i.e., max soil moisture storage [mm] (e.g., 0-600 mm);
  2.52, # BETA the non linear parameter for runoff production [-] (e.g., 0.0-20.0);
  0.473, # k0 storage coefficient for very fast response [timestep] (e.g., 0.0-2.0 days);
  9.06, # k1 storage coefficient for fast response [timestep] (e.g., 2.0-30.0 days);
  142, # k2 storage coefficient for slow response [timestep] (e.g., 30.0-250.0 days);
  50.1, # lsuz threshold storage state, i.e., the very fast response start if exceeded [mm] (e.g., 1.0-100.0 mm);
  2.38, # cperc constant percolation rate [mm/timestep] (e.g., 0.0-8.0 mm/day);
  10, # bmax maximum base at low flows [timestep] (e.g., 0.0-30.0 days);
  25 # croute free scaling parameter [timestep^2/mm] (e.g., 0.0-50.0 days^2/mm);
)


# set time period
model_in <- indata %>%
  filter(date >= as_date("2017-10-01") & date <= as_date("2022-09-30"))

# set up the model
## THIS IS THE ACTUAL MODEL EXECUTION
modelRun <- TUWmodel(
  prec = model_in$weighted_precip.mm, # precip input
  airt = model_in$Tmean_c, # air temp input
  ep = model_in$PET_mm, # pet input
  area = 1, # one zone for the entire watershed
  param = model_params # input model parameters
)


# get all outputs into a nice df
HBVRun <- tibble(
  Date = model_in$Date, # date
  P_mm = modelRun$prec, # precip
  Tair = modelRun$airt, # air temp
  SWEobs = model_in$weighted_swe.mm, # observed swe
  PET = modelRun$ep,# pet
  Qobs = model_in$Q_mm_day, # observed discharge
  Qsim = modelRun$q[1, ], # simulated discharge
  Qsurf = modelRun$q0[1, ], # surface runoff
  Qsubsurf = modelRun$q1[1, ], # subsurface flow
  Qbase = modelRun$q2[1, ], # groundwater flow
  Rain = modelRun$rain[1, ], # simulated rain
  Snow = modelRun$snow[1, ], # simulated snowfall
  Melt = modelRun$melt[1, ], # simulated melt
  SWEsim = modelRun$swe[1, ], # simulated swe
  Soilmoist = modelRun$moist[1, ], # simulated soil storage
  AET = modelRun$eta[1, ], # simulated evapotranspiration
  StorageUpper = modelRun$suz[1, ], # upper storage value
  StorageLower = modelRun$slz[1, ] # lower storage value
)

#Trim out the warm up period
OutTrim <- HBVRun %>% slice(366:n())

#Calculate NSE
NSE <- 1 - ((sum((OutTrim$Qsim - OutTrim$Qobs) ^ 2)) / 
                 sum((OutTrim$Qobs - mean(OutTrim$Qobs)) ^ 2))

print(NSE)
[1] -0.3496303

Plot observed and model simulations

Generate plots that include and compare the different modeled fluxes from your best NSE. Some of those fluxes can be immediately compared to observed data (e.g., runoff or SWE), while others only exist in simulated form (e.g., storages or outflows of the various runoff components) and need to be assessed with the perceptual model in mind.
Make sure that the axes are properly labeled when you create plots. The script below will get you started.

# Add date to the HBVRun result tibble
HBVRun <- as.data.frame(HBVRun)
HBVRun$Date <- model_in$date
str(HBVRun)
'data.frame':   1826 obs. of  18 variables:
 $ P_mm        : num  26.78 7.65 1.91 0 0 ...
 $ Tair        : num  0.8 -1.6 -0.7 6.2 6.65 0.25 3.2 2.5 -7.8 -1.8 ...
 $ SWEobs      : num  13.3 46.7 53.4 53.4 51.2 ...
 $ PET         : num  1.3 1.15 1.23 1.84 1.76 ...
 $ Qobs        : num  0.282 0.243 0.234 0.23 0.231 ...
 $ Qsim        : num  0.0135 0.0418 0.0661 0.0531 0.0398 ...
 $ Qsurf       : num  0 0 0 0 0 0 0 0 0 0 ...
 $ Qsubsurf    : num  0.1343 0 0 0 0.0421 ...
 $ Qbase       : num  0.0342 0.0434 0.0431 0.0569 0.0732 ...
 $ Rain        : num  10.7 0 0 0 0 ...
 $ Snow        : num  16.07 7.65 1.91 0 0 ...
 $ Melt        : num  2.04 0 0 11.76 12.57 ...
 $ SWEsim      : num  14.825 22.858 24.866 13.101 0.526 ...
 $ Soilmoist   : num  60.1 60.1 60.1 68 75.9 ...
 $ AET         : num  1.3 0 0 1.84 1.76 ...
 $ StorageUpper: num  1.36 0 0 0 0.52 ...
 $ StorageLower: num  4.85 6.16 6.12 8.08 10.39 ...
 $ Date        : Date, format: "2017-10-01" ...
# Round the NSE for display
nse_label <- paste("NSE =", round(NSE, 3))

q_plot <- ggplot(data = HBVRun) +
  geom_line(aes(x = Date, y = Qobs, color = "Qobs")) +  # Qobs
  geom_line(aes(x = Date, y = Qsim, color = "Qsim")) +  # Qsim
  annotate("text",
           x = max(HBVRun$Date) - 100,  # Move label # days from the end
           y = max(HBVRun$Qobs, na.rm = TRUE),
           label = nse_label,
           hjust = 1, vjust = 1.5, size = 5, fontface = "bold") +
  labs(x = NULL, y = "Q (mm/day)", color = NULL, title = "Qobs and Qsim")


# Make it interactive with plotly
ggplotly(q_plot)
NA

More plots

# Swe
swe_plot <- ggplot(data = HBVRun) +
  geom_line(aes(x = Date, y = SWEobs, color = "SWEobs")) + # SWEobs
  geom_line(aes(BLANK)) + # SWEsim
  labs(x = {}, y = "SWE (mm)", color = {})
ggplotly(swe_plot)
# Q0, Q1, Q2
q_bucket_plot <- ggplot(data = HBVRun) +
  geom_line(aes(x = Date, y = Qsurf, color = "Qsurf")) + # Qsurf
  geom_line(aes(x = Date, y = Qsubsurf, color = "Qsubsurf")) + #Qsubsurf
  geom_line(aes(x = Date, y = Qbase, color = "Qbase")) + # Qbase
  labs(x = {}, y = "Q (mm)", color = {}, title = "Q0, Q1, and Q2")
ggplotly(q_bucket_plot)
LS0tCnRpdGxlOiAiSEJWIE1vZGVsIgphdXRob3I6ICJZT1VSIE5BTUUgSEVSRSIKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKCiNMb2FkIHBhY2thZ2VzCiMgcGtnVGVzdCBpcyBhIGhlbHBlciBmdW5jdGlvbiB0byBsb2FkIHBhY2thZ2VzIGFuZCBpbnN0YWxsIHBhY2thZ2VzIG9ubHkgd2hlbiB0aGV5IGFyZSBub3QgaW5zdGFsbGVkIHlldC4KCnBrZ1Rlc3QgPC0gZnVuY3Rpb24oeCkKewogIGlmICh4ICVpbiUgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpID09IEZBTFNFKSB7CiAgICBpbnN0YWxsLnBhY2thZ2VzKHgsIGRlcGVuZGVuY2llcz0gVFJVRSkKICB9CiAgbGlicmFyeSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCn0KbmVlZGVkUGFja2FnZXMgPC0gYygidGlkeXZlcnNlIiwgImx1YnJpZGF0ZSIsICJicm9vbSIsICJUVVdtb2RlbCIsICJwbG90bHkiKSAKCmZvciAocGFja2FnZSBpbiBuZWVkZWRQYWNrYWdlcyl7cGtnVGVzdChwYWNrYWdlKX0KYGBgCgpJbiB0aGlzIGV4ZXJjaXNlLCB3ZSB3aWxsIHB1bGwgdG9nZXRoZXIgbWFueSBhc3BlY3RzIG9mIHdoYXQgd2UgaGF2ZSBsZWFybmVkIHNvIGZhciB0byBjYWxpYnJhdGUgdGhlIEhCViBtb2RlbCB0byB3ZWlnaHRlZCBkYXRhIGZyb20gdGhlIEZyYXNlciBFeHBlcmltZW50YWwgRm9yZXN0IGluIENvbG9yYWRvIHVzaW5nIHByZWNpcGl0YXRpb24vcnVub2ZmIGFuZCBwb3RlbnRpYWwgZXZhcG90cmFuc3BpcmF0aW9uIChQRVQpIGRhdGEgZGVyaXZlZCBmcm9tIHRoZSBtZXRob2RzIGV4cGxvcmVkIGluIHRoZSBzbm93bWVsdCBhbmQgZXZhcG90cmFuc3BpcmF0aW9uIG1vZHVsZXMuIAoKSEJWIGlzOgpJbiB0aGUgcHJldmlvdXMgbGFicywgd2UgaGF2ZSB3b3JrZWQgd2l0aCBzaW5nbGUtcHJvY2VzcyBtb2RlbHMuIEhCViBpcyBtb3JlIGNvbXBsZXggcHJvY2Vzcy1iYXNlZCBtb2RlbCB1c2luZyBtYW55IHBhcmFtZXRlcnMgdG8gZGVzY3JpYmUgdGhlIHBoeXNpY2FsIHByb2Nlc3NlcyBvZiB0aGUgaHlkcm9sb2dpYyBjeWNsZQpodHRwczovL3JwdWJzLmNvbS9zZGhha2FsLzg0ODIzNgoKIVtdKGltYWdlcy9IQlYtc2NoZW0tU2hyZXN0aGEtU29sb21hbnRpbmUtMjAwOC5wbmcgIkhCViBNb2RlbCIpCgpGcm9tOiBEdXJnYSBMYWwgU2hyZXN0aGEgJiBEaW1pdHJpIFAuIFNvbG9tYXRpbmUgKDIwMDgpIERhdGHigJBkcml2ZW4gYXBwcm9hY2hlcyBmb3IgZXN0aW1hdGluZyB1bmNlcnRhaW50eSBpbiByYWluZmFsbOKAkHJ1bm9mZiBtb2RlbGxpbmcsIEludGVybmF0aW9uYWwgSm91cm5hbCBvZiBSaXZlciBCYXNpbiBNYW5hZ2VtZW50LCA2OjIsIDEwOS0xMjIsIERPSTogMTAuMTA4MC8xNTcxNTEyNC4yMDA4Ljk2MzUzNDEKCkhCViB2ZXJzaW9ucyB3aXRoIGEgR1VJIGV4aXN0cywgYnV0IHRoZSBkYXRhIG1hbmlwdWxhdGlvbiBpcyBtb3JlIGNvbnZlbmllbnQgaW4gYSBjb2RpbmcgZW52aXJvbm1lbnQsIGFuZCB3ZSB3YW50IHlvdSB0byBiZSBhYmxlIHRvIHNlZSAndW5kZXIgdGhlIGhvb2QnLiBJbnN0ZWFkIG9mIGRlYWxpbmcgd2l0aCB0aGUgaW5uZXIgd29ya2luZ3Mgb2YgdGhlIG1vZGVsIHRvbyBtdWNoLCB3ZSB3aWxsIHB1dCB0aGUgZm9jdXMgb24gaW1wb3J0aW5nIGFuZCBvcmdhbml6aW5nIHRoZSBkYXRhLCBnZXR0aW5nIHRoZSBtb2RlbCBydW5uaW5nLCBtYW51YWwgb3B0aW1pemF0aW9uLiAgCgpUaGUgSEJWIHJlYWxpemF0aW9uIHdlIHdpbGwgYmUgdXNpbmcgaXMgY29udGFpbmVkIGluIHRoZSBSIHBhY2thZ2UgVFVXbW9kZWwuIFBsZWFzZSBzZWFyY2ggdGhhdCBwYWNrYWdlIGluIHlvdXIgYnJvd3NlciBhbmQgZmFtaWxpYXJpemUgeW91cnNlbGYgd2l0aCBpdCAodGhhdCB3aWxsIGJlIHRoZSBmaXJzdCBzdGVwKS4gVFVXIHNpbXBseSBtZWFucyAiVGVjaG5pc2NoZSBVbml2ZXJzaXRhZXQgV2llbiIsIG9yIFZpZW5uYSBVbml2ZXJzaXR5IG9mIFRlY2hub2xvZ3kuIFRoZSBtb2RlbCBpcyBzbGlnaHRseSBkaWZmZXJlbnQgZnJvbSB0aGUgb3JpZ2luYWwgSEJWIGJ1dCBzdGlsbCBzaW1pbGFyIGVub3VnaCB0byBjYWxsIGl0IEhCVi4gV2UgYWxzbyBuZWVkIHRvIHVuZGVyc3RhbmQgdGhlIGFyZ3VtZW50cyBhbmQgcGFyYW1ldGVycyByZXF1aXJlZCBmb3IgdGhlIG1vZGVsLiAKClR5cGUgJz9UVVdtb2RlbCcgaW4geW91ciBjb25zb2xlLiBUaGUgcGFja2FnZSBjb21lcyB3aXRoIGFuIGV4YW1wbGUgZGF0YXNldCwgYW5kIHlvdSBjYW4gcnVuIGV4YW1wbGVzIGVpdGhlciBieSBjb3B5aW5nIGFuZCBwYXN0aW5nIHRoZSBkYXRhKCksIFRVV21vZGVsKCkgYW5kIHBsb3RzIGludG8geW91ciBjb25zb2xlLCBvciB5b3UgY2FuIGZpbmQgYW5kIGNsaWNrICdSdW4gZXhhbXBsZXMnIHVuZGVyIHRoZSAqKkV4YW1wbGVzKiogaGVhZGVyIGFuZCB2aWV3IHRoZSBzY3JpcHQgYW5kIHBsb3Qgb3V0cHV0cyBpbiB0aGUgSGVscCB3aW5kb3cuIFRoZSBmaXJzdCBleGFtcGxlIHNob3dzIGhvdyB0aGUgICdUVVdtb2RlbCcgY2FuIGJlIHJ1biBnaXZlbiBzcGVjaWZpY2F0aW9ucyBmb3IgYSBsb25nIHNldCBvZiBwYXJhbWV0ZXJzIChwYXJhbSkuIFlvdSBjYW4gcHJvdmlkZSB0aGUgbW9kZWwgd2l0aCBwcmVjaXAsIGFpciB0ZW1wZXJhdHVyZSwgYXJlYSBhbmQgRVQgYWxvbmcgd2l0aCB0aGUgcGFyYW1ldGVyIHNldCBhbmQgaXQgd2lsbCBzaW11bGF0ZSBTV0UsIHNub3dtZWx0IGFuZCBkaXNjaGFyZ2UuIFdlIGNhbiBvYnRhaW4gbWVhc3VyZW1lbnRzIGZvciBlYWNoIG9mIHRoZXNlIHZhcmlhYmxlcywgc28gd2Ugd2lsbCBpbXBvcnQgYWxsIG9mIHRoaXMgZGF0YSBhbmQgdGVzdCB0aGUgZml0IG9mIHRoZSBzaW11bGF0ZWQgZGF0YS4gCgpodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvVFVXbW9kZWwvVFVXbW9kZWwucGRmICAKCiMjIyBJbXBvcnQgZGF0YTogCldlIHdpbGwgZ2VuZXJhdGUgYSBjb25jZXB0dWFsIHJ1bm9mZiBtb2RlbCBzdGFydGluZyB3aXRoOjxicj4KLSBSYWluTWVsdFdlaWdodGVkX21tIC0tPiBsaXF1aWQgaW5wdXQgdG8gdGhlIGdyb3VuZCwgY29tYmluYXRpb24gb2YgcmFpbiBhbmQgbWVsdDxicj4KLSBQV2VpZ2h0ZWRfbW0gLS0+IFByZWNpcGl0YXRpb24gbWVhc3VyZWQgYXQgdGhlIFNOT1RFTCBzaXRlcywgYm90aCBsaXF1aWQgYW5kIGZyb3plbi4gVGhpcyBpcyBOT1Qgd2F0ZXIgdGhhdCB3ZW50IGludG8gdGhlIGdyb3VuZCBhdCB0aGF0IHBvaW50LiBUaGlzIGlzLCBob3dldmVyLCB0aGUgUCBpbnB1dCB0aW1lIHNlcmllcyBmb3IgdGhlIEhCViBtb2RlbC48YnI+Ci0gU3dlV2VpZ2h0ZWRfbW0gLS0+IFNub3cgd2F0ZXIgZXF1aXZhbGVudCBhdCB0aGUgU05PVEVMIHNpdGVzLiBXZSBjYW4gdXNlIHRoaXMgdG8gZXZhbHVhdGUgb3VyIHNub3cgcm91dGluZS48YnI+Ci0gVGVtcFdlaWdodGVkIC0tPiBFaXRoZXIgZGFpbHkgbWVhbiwgbWluLCBvciBtYXguIFdlIHdpbGwgdXNlIHRoZSBtZWFuLgotIERpc2NoYXJnZV9tbSAtLT4gUSBvYnNlcnZlZCBhdCB0aGUgb3V0bGV0Ljxicj4KLSBFVCAtLT4gUG90ZW50aWFsIEV2YXBvdHJhbnNwaXJhdGlvbiBjYWxjdWxhdGVkIHVzaW5nIHJlbGF0aXZlIGh1bWlkaXR5IGFuZCB0ZW1wZXJhdHVyZS48YnI+CgojIyMgUmVwbyBsaW5rCltEb3dubG9hZCB0aGUgcmVwbyBmb3IgdGhpcyBsYWIgSEVSRV0oaHR0cHM6Ly9naXRodWIuY29tL3RwY292aW5vLzA4X2hidl9tb2RlbHMtLmdpdCl7dGFyZ2V0PSJfYmxhbmsifQoKIyMjIExhYndvcmsgKDIwIHBudHMpCgpPdXIgZmlyc3Qgc3RlcHMgd2lsbCBiZSB0byBpbXBvcnQgYW5kIGZvcm1hdCB0aGUgZGF0YS4gQXMgeW91IG1pZ2h0IHJlY2FsbCBmcm9tIHRoZSBwcmV2aW91cyBtb2R1bGVzLCB0aGlzIHN0ZXAgY2FuIHJlcXVpcmUgdGhlIG1vc3Qgc2NyaXB0IGFuZCAnd29yaycsIGJ1dCBpcyBjcml0aWNhbCB0byBhIHZhbGlkIG1vZGVsIG91dHB1dC4gSW4gdGhpcyBhc3NpZ25tZW50LCB3ZSBoYXZlIHNpbXBsaWZpZWQgbXVjaCBvZiB0aGUgZGF0YSBjb2xsZWN0aW9uIGZvciB5b3UsIGFzIHRoZSBzdGVwcyBhcmUgb25lcyB5b3UgaGF2ZSBhbHJlYWR5IGNvbXBsZXRlZCBpbiBwcmV2aW91cyBtb2R1bGVzLiAKSW4gdGhlIC5jc3YgaW1wb3J0ZWQgYmVsb3csIHdlIHN0YXJ0ZWQgYnkgY29sbGVjdGluZyB0aGUgc2FtZSBTTk9URUwgZGF0YSB0aGF0IHlvdSB1c2VkIGluIHRoZSBzbm93bWVsdCBtb2R1bGUsIGJ1dCBkb3dubG9hZGVkIGZvciBhIGdyZWF0ZXIgZGF0ZSByYW5nZSAod2F0ZXIgeWVhcnMgMjAxOC0yMDIyKSAoZGF0ZSwgU1dFIGRlcHRoIGluIG1tLCBhbmQgZGFpbHkgcHJlY2lwaXRhdGlvbiAobW0pKSBIb3dldmVyLCB5b3Ugd2lsbCBub3RpY2UgdGhhdCB0aGUgY29sdW1uIG5hbWVzIG9mIHRoZSBwcm92aWRlZCB0YWJsZSBjb250YWluICd3ZWlnaHRlZF8nLiAKCmBgYHtyfQojIEltcG9ydCBkYXRhCmluZGF0YSA8LSByZWFkLmNzdigiSEJWX2RhdGEvd2VpZ2h0ZWRfZGF0YV9mb29sX0hCVi5jc3YiKSU+JQogIG11dGF0ZShkYXRlID0geW1kKGRhdGUpKSAlPiUKICByZW5hbWUoUV9tM19zID0gbTNfcywgUV9tbV9kYXkgPSBtbV9kYXksIHJ1bm9mZl9pbnB1dC5tbSA9IGlucHV0Lm1tICkKCnN0cihpbmRhdGEpCmBgYAoKQXMgd2Ugbm90ZWQgaW4gdGhlIFNub3dtZWx0IG1vZHVsZSwgZmFjdG9ycyBzdWNoIGFzIGVsZXZhdGlvbiBhbmQgdmVnZXRhdGlvbiB3aWxsIGFmZmVjdCB0aGUgb2Ygc25vdy10by1ydW5vZmYgcmF0ZS4gU2ltaWxhcmx5LCB0ZW1wZXJhdHVyZSBhbmQgcHJlY2lwaXRhdGlvbiBkaWZmZXIgd2l0aCBlbGV2YXRpb24sIG1lYW5pbmcgdGhhdCBTTk9URUwgZGF0YSBmcm9tIGEgc2luZ2xlIGxvY2F0aW9uIG1heSBub3QgZnVsbHkgcmVwcmVzZW50IGNvbmRpdGlvbnMgYWNyb3NzIHRoZSBlbnRpcmUgd2F0ZXJzaGVkLgoKVG8gYWNjb3VudCBmb3IgdGhlc2UgdmFyaWF0aW9ucywgdGhlICJ3ZWlnaHRlZCIgdmFsdWVzIGZvciB0aGlzIGV4ZXJjaXNlIGhhdmUgYmVlbiBhZGp1c3RlZCB1c2luZyBsaW5lYXIgc2NhbGluZyByZWxhdGlvbnNoaXBzIHRoYXQgZXN0aW1hdGUgYXZlcmFnZSBjb25kaXRpb25zIGFjcm9zcyB0aGUgd2F0ZXJzaGVkLiBUaGUgYWRqdXN0bWVudHMgdXNlIGVsZXZhdGlvbi1wcmVjaXBpdGF0aW9uIGFuZCBlbGV2YXRpb24tdGVtcGVyYXR1cmUgcmVsYXRpb25zaGlwcyBkZXJpdmVkIGZyb20gaW52ZXJzZSBkaXN0YW5jZSB3ZWlnaHRpbmcgdG8gYmV0dGVyIGFwcHJveGltYXRlIHNwYXRpYWxseSBkaXN0cmlidXRlZCBoeWRyb2xvZ2ljYWwgaW5wdXRzIHJhdGhlciB0aGFuIHJlbHlpbmcgb24gYSBzaW5nbGUgcG9pbnQgbWVhc3VyZW1lbnQuCgoKIVtdKGltYWdlcy9wcmVjaXBfc3BhdGlhbF9pbnRlcnAucG5nICJTcGF0aWFsIEludGVycG9sYXRpb24iKQoKCklmIHlvdSBhcmUgaW50ZXJlc3RlZCwgeW91IGNhbiBzdGFydCBleHBsb3Jpbmcgc3BhdGlhbCBpbnRlcnBvbGF0aW9uIHdpdGg6CjEuIFRoaWVzc2VuIHBvbHlnb25zCiFbVGhpZXNzZW4gcG9seWdvbnNdKGh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvdGh1bWIvZC9kOS9Wb3Jvbm9pX2dyb3d0aF9ldWNsaWRlYW4uZ2lmLzQ0MHB4LVZvcm9ub2lfZ3Jvd3RoX2V1Y2xpZGVhbi5naWYpCjIuIEludmVyc2UgZGlzdGFuY2Ugd2VpZ2h0aW5nCjMuIEtyaW5naW5nIG1ldGhvZHMKdG8gZGV0ZXJtaW5lIGlmIGFueSBvZiB0aGVzZSBhcmUgYXBwbGljYWJsZSB0byB5b3VyIHN0dWR5IGFyZWEuCgpPdGhlciBjb2x1bW5zIGluIHRoaXMgZGF0YSBpbmNsdWRlOgoqKlFfbTNfcyBhbmQgUV9tbV9kYXkqKiAtIERpc2NoYXJnZSAoUSkgY29sbGVjdGVkIGF0IHRoZSBGb29sIENyZWVrIG91dGxldCBieSBVU0ZTLCBpbiB1bml0cyBvZiBjdWJpYyBtZXRlcnMgcGVyIHNlY29uZCBhbmQgbW0gcGVyIGRheSBmcm9tIEFwcmlsIHVudGlsIE9jdG9iZXIuCioqVG1heF9jLCBUbWluX2MgYW5kIFRtZWFuX2MqKiAtIFR5cGljYWxseSwgd2UgY291bGQgZmluZCBkYWlseSBtZWFuLCBtYXggYW5kIG1pbmltdW0gdGVtcGVyYXR1cmVzIGluIHRoZSBTTk9URUwgZGF0YXNldHMsIGhvd2V2ZXIsIHRoaXMgcGFydGljdWxhciBzdGF0aW9uIGlzIG1pc3NpbmcgdGVtcGVyYXR1cmUgZGF0YSAoZHVlIHRvIHJlc3RyaWN0aW9ucyBvbiB0ZWNobmljYWwgYWNjZXNzIGluIDIwMjApLCBzbyB3ZSByZXRyaWV2ZWQgdGVtcGVyYXR1cmUgZGF0YSBmcm9tIEdyaWRNRVQgdGhyb3VnaCBbQ2xpbWF0ZSBFbmdpbmVdKGh0dHBzOi8vYXBwLmNsaW1hdGVlbmdpbmUub3JnL2NsaW1hdGVFbmdpbmUpLiBUaGlzIGhpZ2hsaWdodHMgdGhlIGltcG9ydGFuY2Ugb2YgZXZhbHVhdGluZyBlYWNoIHZhcmlhYmxlIGZvciBjb21wbGV0ZW5lc3MuIEl0IHdpbGwgc2F2ZSB5b3UgdGhlIGhlYWRhY2hlIG9mIHJ1bm5pbmcgdGhlIGVudGlyZSB3b3JrZmxvdywgb25seSB0byBmaW5kIHRoYXQgbW9kZWwgb3V0cHV0cyBjYW5ub3QgYmUgc2ltdWxhdGVkIGZvciB0aGUgbGF0ZXIgaGFsZiBvZiAyMDIwIGR1ZSB0byBtaXNzaW5nIGlucHV0IGRhdGEuCioqUkhtaW4sIFJIbWF4KiogLSBSZWxhdGl2ZSBodW1pZGl0eSBkYWlseSBtaW4gYW5kIG1heCwgYWxzbyBmcm9tIEdyaWRNRVQsIGFjY2Vzc2VkIHRocm91Z2ggQ2xpbWF0ZSBFbmdpbmUKKipTV0VkaWZmLm1tLCBQZGlmZi5tbSBhbmQgcnVub2ZmX2lucHV0Lm1tKiogLSBhbGwgZGFpbHkgb3V0cHV0cyBvZiBhIHRlbXBlcmF0dXJlIGJhc2VkIHNub3dtZWx0IG1vZGVsICh0aGUgc2FtZSBhcyBpbiB0aGUgc25vd21lbHQgbW9kdWxlKS4gcnVub2ZmX2lucHV0IGlzIHRoZSBlc3RpbWF0ZWQgZGFpbHkgaW5wdXQgdG8gdGhlIHN0cmVhbSBmcm9tIG1lbHRlZCBzbm93IGFuZCBsaXF1aWQgcHJlY2lwaXRhdGlvbiBjb21iaW5lZC4KCktlZXAgaW4gbWluZCB0aGF0IHlvdSBjYW4gcGxvdCBtb3JlIHRoYW4gdHdvIHZhcmlhYmxlcyBpbiBhIHNpbmdsZSBwbG90LCBidXQgdGhleSB3aWxsIGJlIG1vc3QgaGVscGZ1bCBpZiB5b3UgZ3JvdXAgdmFyaWFibGVzIHdpdGggYSBzaW1pbGFyIHktc2NhbGUuIEZvciBleGFtcGxlLCBjdW11bGF0aXZlIHByZWNpcGl0YXRpb24gb3IgU1dFIHZhbHVlcyB3aWxsIGhhdmUgYSBkaWZmZXJlbnQgcmFuZ2UgdGhhbiB2YXJpYWJsZXMgdGhhdCByZXByZXNlbnQgZGFpbHkgbWVhc3VyZW1lbnRzIGxpa2UgJ2lucHV0X21tJy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBhZGQgYSBzZWNvbmRhcnkgeS1heGlzIHRvIHlvdXIgcGxvdC4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGluZGF0YSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBkYXRlLCB5ID0gcnVub2ZmX2lucHV0Lm1tLCBjb2xvciA9ICJydW5vZmZfaW5wdXQubW0iKSwgc2l6ZSA9IDAuNSkgKyAgIyBBc3NpZ24gYSBsYWJlbCBmb3IgbGVnZW5kCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRhdGUsIHkgPSBRX21tX2RheSwgY29sb3IgPSAibW0vZGF5IiksIHNpemUgPSAwLjUpICsgICMgQXNzaWduIGEgZGlmZmVyZW50IGxhYmVsCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRhdGUsIHkgPSB3ZWlnaHRlZF9wcmVjaXAubW0sIGNvbG9yID0gIndlaWdodGVkX3ByZWNpcC5tbSIpLCBzaXplID0gMC41KSArICAjIEFzc2lnbiBhIGRpZmZlcmVudCBsYWJlbAogIGdlb21fcG9pbnQoYWVzKHggPSBkYXRlLCB5ID0gUGRpZmYubW0sIGNvbG9yID0gIlBkaWZmLm1tIiksIHNpemUgPSAwLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygicnVub2ZmX2lucHV0Lm1tIiA9ICJibHVlIiwgIm1tL2RheSIgPSAicmVkIiwgIndlaWdodGVkX3ByZWNpcC5tbSIgPSAiZ3JlZW4iLCAiUGRpZmYubW0iID0gJ3B1cnBsZScpKSArICAjIEN1c3RvbWl6ZSBjb2xvcnMKICBsYWJzKGNvbG9yID0gIkRpc2NoYXJnZSBVbml0cyIpICsgICMgTGVnZW5kIHRpdGxlCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIDIsOTMwbS4Kd2F0ZXJzaGVkX2FyZWFfbTIgPC0gMjY0MDAwMCAKCk5vdGUgdGhhdCB3aGlsZSB0aGUgc3RyZWFtIGlzIHNub3ctY292ZXJlZCwgdGhlcmUgYXJlIG5vIHN0YWdlL2Zsb3cgbWVhc3VyZW1lbnRzIGJlaW5nIG1hZGUgYXQgdGhpcyBzaXRlLiBGb3IgbWFueSBvZiBvdXIgY2FsY3VsYXRpb25zIHRvIHdvcmssIHdlIHdpbGwgbm90IHdhbnQgTkEgaW4gb3VyIGRhdGEgZnJhbWVzLiBJbiB0aGlzIGRhdGEgc2V0LCBpZiB3ZSB2aWV3IHRoZSB0YWJ1bGFyIGRhdGEsIHRoZSBlbmQgZGlzY2hhcmdlIHJlYWRpbmcgKFFfbW1fZGF5KSwgaXMgdmVyeSBzaW1pbGFyIHRvIHRoZSBmaXJzdCBpbiB0aGUgZm9sbG93aW5nIGNhbGVuZGFyIHllYXIuIEZvciB0aGlzIGV4YW1wbGUsIHdlIHdpbGwgdGhlbiBmaWxsIHRoZSBOQSB2YWx1ZXMgd2l0aCB0aGUgbWVhbiBvZiB0aGUgZmluYWwgYW5kIGZpcnN0IHJlYWRpbmdzIGZvciBlYWNoIHdpbnRlciAoT2N0IC0gQXByaWwpIE5BIHN0cmluZy4KCmBgYHtyfQojIFJhdGhlciB0aGFuIHNjcm9sbGluZyB0aHJvdWdoIGEgZGF0YWZyYW1lLCB0aGlzIGdpdmVzIHVzIGEgc3VtIG9mICdOQScgcm9zIGluIHRoaXMgY29sdW1uCnN1bShpcy5uYShpbmRhdGEkUV9tbV9kYXkpKQpgYGAKCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGZpbGwgTkEgdmFsdWVzIGluIFFfbW1fZGF5IGR1cmluZyB3aW50ZXIgKE9jdCAtIEFwcikKZmlsbF9uYV93aW50ZXIgPC0gZnVuY3Rpb24oZGYpIHsKICBkZiA8LSBkZiAlPiUKICAgIGFycmFuZ2UoZGF0ZSkgJT4lICMgRW5zdXJlIGRhdGEgaXMgc29ydGVkCiAgICBtdXRhdGUoCiAgICAgIG1vbnRoID0gbW9udGgoZGF0ZSksCiAgICAgIGlzX3dpbnRlciA9IG1vbnRoICVpbiUgYygxMCwgMTEsIDEyLCAxLCAyLCAzLCA0KSAjIElkZW50aWZ5IHdpbnRlciBtb250aHMKICAgICkKICAKICAjIElkZW50aWZ5IE5BIHN0cmV0Y2hlcyBpbiB3aW50ZXIgbW9udGhzCiAgbmFfaW5kaWNlcyA8LSB3aGljaChpcy5uYShkZiRRX21tX2RheSkgJiBkZiRpc193aW50ZXIpCiAgCiAgZm9yIChpZHggaW4gbmFfaW5kaWNlcykgewogICAgIyBGaW5kIHRoZSBsYXN0IG5vbi1OQSBiZWZvcmUgdGhlIGN1cnJlbnQgTkEKICAgIHByZXZfdmFsdWUgPC0gZGYkUV9tbV9kYXlbbWF4KHdoaWNoKCFpcy5uYShkZiRRX21tX2RheVsxOihpZHggLSAxKV0pKSldCiAgICAKICAgICMgRmluZCB0aGUgbmV4dCBub24tTkEgYWZ0ZXIgdGhlIGN1cnJlbnQgTkEKICAgIG5leHRfdmFsdWUgPC0gZGYkUV9tbV9kYXlbbWluKHdoaWNoKCFpcy5uYShkZiRRX21tX2RheVsoaWR4ICsgMSk6bnJvdyhkZildKSkgKyBpZHgpXQogICAgCiAgICAjIFJlcGxhY2UgdGhlIE5BIHdpdGggdGhlIGF2ZXJhZ2Ugb2YgcHJldl92YWx1ZSBhbmQgbmV4dF92YWx1ZQogICAgaWYgKCFpcy5uYShwcmV2X3ZhbHVlKSAmICFpcy5uYShuZXh0X3ZhbHVlKSkgewogICAgICBkZiRRX21tX2RheVtpZHhdIDwtIChwcmV2X3ZhbHVlICsgbmV4dF92YWx1ZSkgLyAyCiAgICB9CiAgfQogIAogIHJldHVybihkZikKfQoKIyBBcHBseSB0aGUgZnVuY3Rpb24KaW5kYXRhIDwtIGZpbGxfbmFfd2ludGVyKGluZGF0YSkKYGBgCgpMZXQncyB0cnkgb3VyIHF1aWNrIGNoZWNrIGFnYWluOiAKYGBge3J9CiMgTm93IHdlIHNob3VsZCBzZWUgemVybyBOQSBpbiB0aGlzIGNvbHVtbgpzdW0oaXMubmEoaW5kYXRhJFFfbW1fZGF5KSkKYGBgCgpOZXh0LCB3ZSBuZWVkIHRvIGFkZCBkYWlseSBwb3RlbnRpYWwgZXZhcG90cmFuc3BpcmF0aW9uIChQRVQpIHRvIHRoZSBkYXRhc2V0LiBUaGUgZXZhcG90cmFuc3BpcmF0aW9uIG1vZHVsZSBjb3ZlcmVkIHNvbWUgb2YgdGhlIG51bWVyb3VzIHByZS1idWlsdCBmdW5jdGlvbnMgYXZhaWxhYmxlIGluIHZhcmlvdXMgUiBwYWNrYWdlcyBkZXNpZ25lZCBmb3IgRVQgZXN0aW1hdGlvbi4gRm9yIGluc3RhbmNlLCB0aGUgJ0V2YXBvdHJhbnNwaXJhdGlvbicgcGFja2FnZSBwcm92aWRlcyBFVCBlc3RpbWF0ZXMgZGVyaXZlZCBmcm9tIGFwcHJveGltYXRlbHkgMjAgZGlzdGluY3QgZXF1YXRpb25zIG9yIHZhcmlhdGlvbnMuIFRoZXNlIGZ1bmN0aW9ucyByZXF1aXJlIHByZWNpc2UgZGF0YSBmb3JtYXR0aW5nIHRvIGVuc3VyZSBjb21wYXRpYmlsaXR5IHdpdGggdGhlIGZ1bmN0aW9uIGFyZ3VtZW50cy4gVG8gaGVscCB5b3Ugc3RydWN0dXJlIHlvdXIgZnVuY3Rpb24gaW5wdXRzIHNpbWlsYXJseSwgbWFueSBwYWNrYWdlcyBjb21lIHdpdGggZXhhbXBsZSBkYXRhc2V0cyBpbiB0aGVpciBkb2N1bWVudGF0aW9uLiBTUEVJIGlzIGFub3RoZXIgcGFja2FnZSB0aGF0IG9mZmVycyBFVCBmdW5jdGlvbnMuIFRoZSBnaXRodWIgcmVwb3NpdG9yeSBmb3IgdGhpcyBwYWNrYWdlIGhhcyBiZWVuIHVwZGF0ZWQgZmFpcmx5IHJlY2VudGx5LCB3aGljaCBjYW4gYmUgaW1wb3J0YW50IHRvIHZlcmlmeS4gCgpXZSBjaG9zZSB0byB3cml0ZSBvdXIgb3duIGZ1bmN0aW9uIGhlcmUgc28geW91IGNvdWxkICdzZWUgdW5kZXIgdGhlIGhvb2QnLiAgCk5vdCBhbGwgcGFja2FnZXMgYXJlIGVxdWFsbHkgbWFpbnRhaW5lZCwgYXMgdGhleSBhcmUgb2Z0ZW4gZGV2ZWxvcGVkIGJ5IHJlc2VhcmNoZXJzIG9yIG1vZGVsZXJzIHRvIGltcHJvdmUgdGhlIHJlcGVhdGFibHkgb2YgdGhlaXIgd29yaywgYW5kIGNvbnRyaWJ1dGUgdG8gdGhlIGJyb2FkZXIgc2NpZW50aWZpYyBjb21tdW5pdHkuIE9uY2UgZnVuZGluZyBjZWFzZXMsIG9yIGlmIHRoZSBvcmlnaW5hbCBkZXZlbG9wZXIgbW92ZXMgb24gdG8gbmV3IHByb2plY3RzLCBhIGN1c3RvbSBwYWNrYWdlIG1heSBubyBsb25nZXIgcmVjZWl2ZSB1cGRhdGVzIG9yIHN1cHBvcnQuIEFzIFIsIFJTdHVkaW8gYW5kIG90aGVyIHN1cHBvcnRpbmcgcGFja2FnZXMgYXJlIHVwZGF0ZWQsIGEgcGFja2FnZSBtYXkgYmVjb21lIGRlcHJlY2lhdGVkLiBJZiB0aGUgcGFja2FnZSBzdGlsbCBmdW5jdGlvbnMgY29ycmVjdGx5IGluIHlvdXIgY3VycmVudCBSIHZlcnNpb24gYW5kIGRlcGVuZGVuY2llcywgdGhlcmXigJlzIG5vIGltbWVkaWF0ZSByZWFzb24gdG8gc3RvcCB1c2luZyBpdC4gSG93ZXZlciwgaWYgeW91IGFyZSBjb25jZXJuZWQgdGhhdCBmdXR1cmUgdmVyc2lvbnMgb2YgUiBvciBkZXBlbmRlbmNpZXMgbWlnaHQgYnJlYWsgdGhlIHBhY2thZ2VzIHlvdSB1c2UsIHlvdSBjYW4gY2hlY2sgdGhlIGRldmVsb3BtZW50IGFuZCBtYWludGVuYW5jZSBoaXN0b3J5IG9mIGN1c3RvbSBvciBzcGVjaWFsaXplZCBwYWNrYWdlcyAob3Igd3JpdGUgYSBwYWNrYWdlIG9yIGZ1bmN0aW9uIGZvciB5b3Vyc2VsZiBhcyBleGVtcGxpZmllZCBiZWxvdyEpLgoKSGVyZSBpcyBvdXIgSGFyZ3JlYXZlcyBmdW5jdGlvbiwgYWRhcHRlZCBmcm9tIHRoZSAnRXZhcG90cmFuc3BpcmF0aW9uJyBwYWNrYWdlIHRvIG1pbmltaXplIHJlLWZvcm1hdHRpbmcgb2Ygb3VyIGRhdGFmcmFtZS4gCgpgYGB7cn0KCiMgRnVuY3Rpb24gdG8gY2FsY3VsYXRlIEVUCmNhbGN1bGF0ZV9FVCA8LSBmdW5jdGlvbihkYXRhLCBjb25zdGFudHMsIHRzID0gImRhaWx5IiwgbWVzc2FnZSA9ICJ5ZXMiLCBzYXZlLmNzdiA9ICJubyIsIC4uLikgewogIAogICMgQ2hlY2sgZm9yIHJlcXVpcmVkIGRhdGEKICBpZiAoaXMubnVsbChkYXRhJFRtYXgpIHwgaXMubnVsbChkYXRhJFRtaW4pKSB7CiAgICBzdG9wKCJSZXF1aXJlZCBkYXRhIG1pc3NpbmcgZm9yICdUbWF4JyBhbmQgJ1RtaW4nLCBvciAnVGVtcCciKQogIH0KICAKICAjIEhhcmdyZWF2ZXMtU2FtYW5pIEVUIENhbGN1bGF0aW9uCiAgVGEgPC0gKGRhdGEkVG1heCArIGRhdGEkVG1pbikgLyAyCiAgUCA8LSAxMDEuMyAqICgoMjkzIC0gMC4wMDY1ICogY29uc3RhbnRzJEVsZXYpIC8gMjkzKSBeIDUuMjYKICBkZWx0YSA8LSA0MDk4ICogKDAuNjEwOCAqIGV4cCgoMTcuMjcgKiBUYSkgLyAoVGEgKyAyMzcuMykpKSAvICgoVGEgKyAyMzcuMykgXiAyKQogIGdhbW1hIDwtIDAuMDAxNjMgKiBQIC8gY29uc3RhbnRzJGxhbWJkYQogIGRfcjIgPC0gMSArIDAuMDMzICogY29zKDIgKiBwaSAvIDM2NSAqIGRhdGEkSikKICBkZWx0YTIgPC0gMC40MDkgKiBzaW4oMiAqIHBpIC8gMzY1ICogZGF0YSRKIC0gMS4zOSkKICB3X3MgPC0gYWNvcygtdGFuKGNvbnN0YW50cyRsYXRfcmFkKSAqIHRhbihkZWx0YTIpKQogIE4gPC0gMjQgLyBwaSAqIHdfcwogIFJfYSA8LSAoMTQ0MCAvIHBpKSAqIGRfcjIgKiBjb25zdGFudHMkR3NjICogKHdfcyAqIHNpbihjb25zdGFudHMkbGF0X3JhZCkgKiBzaW4oZGVsdGEyKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcyhjb25zdGFudHMkbGF0X3JhZCkgKiBjb3MoZGVsdGEyKSAqIHNpbih3X3MpKQogIENfSFMgPC0gMC4wMDE4NSAqIChkYXRhJFRtYXggLSBkYXRhJFRtaW4pIF4gMiAtIDAuMDQzMyAqIChkYXRhJFRtYXggLSBkYXRhJFRtaW4pICsgMC40MDIzCiAgRVRfSFMuRGFpbHkgPC0gMC4wMTM1ICogQ19IUyAqIFJfYSAvIGNvbnN0YW50cyRsYW1iZGEgKiAoZGF0YSRUbWF4IC0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSRUbWluKSBeIDAuNSAqIChUYSArIDE3LjgpCiAgRVQuRGFpbHkgPC0gRVRfSFMuRGFpbHkKICAKICAjIENyZWF0ZSBZZWFyTW9udGggQ29sdW1uCiAgZGF0YSRZZWFyTW9udGggPC0gYXMuRGF0ZShwYXN0ZSh5ZWFyKGRhdGEkRGF0ZS5kYWlseSksIG1vbnRoKGRhdGEkRGF0ZS5kYWlseSksICIwMSIsIHNlcCA9ICItIikpCiAgCiAgIyBBbm51YWwgYW5kIE1vbnRobHkgQWdncmVnYXRpb25zCiAgRVQuQW5udWFsIDwtIGFnZ3JlZ2F0ZShFVC5EYWlseSB+IHllYXIoWWVhck1vbnRoKSwgZGF0YSA9IGRhdGEsIEZVTiA9IHN1bSkKICBFVC5Nb250aGx5IDwtIGFnZ3JlZ2F0ZShFVC5EYWlseSB+IFllYXJNb250aCwgZGF0YSA9IGRhdGEsIEZVTiA9IHN1bSkKICAKICAjIEVUIGZvcm11bGF0aW5nCiAgRVRfZm9ybXVsYXRpb24gPC0gIkhhcmdyZWF2ZXMtU2FtYW5pIgogIEVUX3R5cGUgPC0gIlJlZmVyZW5jZSBDcm9wIEVUIgogIHJlc3VsdHMgPC0gbGlzdChFVC5EYWlseSA9IEVULkRhaWx5LCBFVC5Nb250aGx5ID0gRVQuTW9udGhseSwgCiAgICAgICAgICAgICAgICAgIEVULkFubnVhbCA9IEVULkFubnVhbCwgRVRfZm9ybXVsYXRpb24gPSBFVF9mb3JtdWxhdGlvbiwgCiAgICAgICAgICAgICAgICAgIEVUX3R5cGUgPSBFVF90eXBlKQogIAogICMgU2F2ZSB0byBDU1YgaWYgcmVxdWlyZWQKICBpZiAoc2F2ZS5jc3YgPT0gInllcyIpIHsKICAgIGZvciAoaSBpbiAxOmxlbmd0aChyZXN1bHRzKSkgewogICAgICBuYW1lciA8LSBuYW1lcyhyZXN1bHRzW2ldKQogICAgICB3cml0ZS50YWJsZShhcy5jaGFyYWN0ZXIobmFtZXIpLCBmaWxlID0gIkVUX0hhcmdyZWF2ZXNTYW1hbmkuY3N2IiwgCiAgICAgICAgICAgICAgICAgIGRlYyA9ICIuIiwgcXVvdGUgPSBGQUxTRSwgY29sLm5hbWVzID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBGLCBhcHBlbmQgPSBUUlVFLCBzZXAgPSAiLCIpCiAgICAgIHdyaXRlLnRhYmxlKGRhdGEuZnJhbWUoZ2V0KG5hbWVyLCByZXN1bHRzKSksIGZpbGUgPSAiRVRfSGFyZ3JlYXZlc1NhbWFuaS5jc3YiLCAKICAgICAgICAgICAgICAgICAgY29sLm5hbWVzID0gRiwgYXBwZW5kID0gVFJVRSwgc2VwID0gIiwiKQogICAgfQogICAgaW52aXNpYmxlKHJlc3VsdHMpCiAgfSBlbHNlIHsKICAgIHJldHVybihyZXN1bHRzKQogIH0KfQpgYGAKCk5vdyB3ZSB3aWxsIGZvcm1hdCB0aGUgaW5wdXRzIHNvIHRoZSBkYXRhIGlzIGVhc2lseSByZWFkIGJ5IHRoZSBmdW5jdGlvbiwgYW5kIHJ1biB0aGUgZnVuY3Rpb24uCgpgYGB7cn0KIyBGb3JtYXQgb3VyIGRhdGEgdG8gZml0IHRoZSBmdW5jdGlvbgpQRVRfZGF0YSA8LSBsaXN0KAogIFRtYXggPSBpbmRhdGEkVG1heCwKICBUbWluID0gaW5kYXRhJFRtaW4sCiAgSiA9IGFzLm51bWVyaWMoZm9ybWF0KGluZGF0YSRkYXRlLCAiJWoiKSksCiAgRGF0ZS5kYWlseSA9IGluZGF0YSRkYXRlCikKCiMgRGVmaW5lIGNvbnN0YW50cwpjb25zdGFudHMgPC0gbGlzdCgKICBFbGV2ID0gMjkwMCwgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBFbGV2YXRpb24gaW4gbWV0ZXJzCiAgbGFtYmRhID0gMi40NSwgICAgICAgICAgICAgICAgICAgICAgICAgICMgTGF0ZW50IGhlYXQgb2YgdmFwb3JpemF0aW9uIGluIE1KLmtnXi0xCiAgbGF0X3JhZCA9IDM5Ljg4ICogcGkgLyAxODAsICAgICAgICAgICAgICMgTGF0aXR1ZGUgaW4gcmFkaWFucwogIEdzYyA9IDAuMDgyMCAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFNvbGFyIGNvbnN0YW50IGluIE1KLm1eLTIubWluXi0xCikKClBFVF9IYXJncmVhdmVzIDwtIGNhbGN1bGF0ZV9FVCgKICBkYXRhID0gUEVUX2RhdGEsCiAgY29uc3RhbnRzID0gY29uc3RhbnRzLAogIHRzID0gImRhaWx5IiwgICAgICAgICMgT3B0aW9uYWw7IGRlZmF1bHRzIHRvICJkYWlseSIKICBtZXNzYWdlID0gInllcyIsICAgICAjIE9wdGlvbmFsOyBwcmludHMgc3VtbWFyeSAKICBzYXZlLmNzdiA9ICJubyIgICAgICAjIE9wdGlvbmFsOyBkbyBub3Qgc2F2ZSByZXN1bHRzIHRvIGEgQ1NWCikKYGBgCgpOb3cgd2UnbGwgYWRkIGRhaWx5IEVUIGludG8gb3VyIG9yaWdpbmFsIGRhdGFmcmFtZToKCmBgYHtyfQpQRVRfbW0gPC0gUEVUX0hhcmdyZWF2ZXMkRVQuRGFpbHkKIyBwdXQgdGhlIGFwcHJveGltYXRlZCBQRVRfbW0gaW50byB0aGUgbGFyZ2VyIGluZGF0YSBkZgppbmRhdGEgPC0gY2JpbmQoaW5kYXRhLCBQRVRfbW0pICAjd2l0aCBjYmluZAoKaGVhZChpbmRhdGEpCmBgYAoKCmBgYHtyfQojIEFubnVhbCBzdW1tYXJ5IHN0YXRzCmluZGF0YV9hbmFseXNpcyA8LSBpbmRhdGEgJT4lCiAgc2VsZWN0KC1kYXRlKSAlPiUKICBncm91cF9ieSh3dHJfeXIpICU+JQogIHN1bW1hcmlzZSgKICAgIHdlaWdodGVkX3ByZWNpcC5tbSA9IHN1bSh3ZWlnaHRlZF9wcmVjaXAubW0sIG5hLnJtID0gVFJVRSksCiAgICBUbWVhbl9jID0gbWVhbihUbWVhbl9jLCBuYS5ybSA9IFRSVUUpLAogICAgc3dlLm1tX21heCA9IG1heCh3ZWlnaHRlZF9zd2UubW0sIG5hLnJtID0gVFJVRSksCiAgICBwY3VtdWwubW1fbWF4ID0gbWF4KHdlaWdodGVkX3BjdW11bC5tbSwgbmEucm0gPSBUUlVFKSwKICAgIFRtYXggPSBtYXgoVG1heF9jLCBuYS5ybSA9IFRSVUUpLAogICAgVG1pbiA9IG1pbihUbWluX2MsIG5hLnJtID0gVFJVRSksCiAgICBRX21tX3N1bSA9IHN1bShRX21tX2RheSwgbmEucm0gPSBUUlVFKSwKICAgIFBFVF9tbV9zdW0gPSBzdW0oUEVUX21tLCBuYS5ybSA9IFRSVUUpLCAKICAgIHJ1bm9mZl9pbnB1dC5tbSA9IHN1bShydW5vZmZfaW5wdXQubW0sIG5hLnJtID0gVFJVRSksCiAgKQoKaW5kYXRhX2FuYWx5c2lzCgpgYGAKCgpgYGB7cn0KIyBZb3VyIHNjcmlwdCBiZWxvdyBzaG91bGQgZml0IHlvdXIgdmFyaWFibGVzIGZyb20geW91ciBzdW1tYXJ5IGRhdGFmcmFtZSBhYm92ZS4gSGVyZSBpcyBhbiBleGFtcGxlIG9mIHdoYXQgYSBzaW1wbGUgd2F0ZXIgYmFsYW5jZSBtaWdodCBsb29rIGxpa2UgaWYgSSBuYW1lZCBteSBzdW1tYXJ5IGRhdGFmcmFtZSBpbmRhdGFfYW5hbHlzaXM6IAoKIyBDYWxjdWxhdGUgdGhlIHJlc2lkdWFsIHdhdGVyIGFmdGVyIGFjY291bnRpbmcgZm9yIFBFVCBhbmQgZGlzY2hhcmdlCnJlc2lkdWFsX3dhdGVyIDwtIGluZGF0YV9hbmFseXNpcyRydW5vZmZfaW5wdXQubW0gLSAoaW5kYXRhX2FuYWx5c2lzJFBFVF9tbV9zdW0gKyBpbmRhdGFfYW5hbHlzaXMkUV9tbV9zdW0pCgojIFZpZXcgdGhlIHJlc2lkdWFsIGZvciBlYWNoIHllYXIKcHJpbnQocmVzaWR1YWxfd2F0ZXIpCmBgYApCeSBzdWJ0cmFjdGluZyBkaXNjaGFyZ2UgYW5kIFBFVCBmcm9tIHJ1bm9mZl9pbnB1dCwgd2XigJlyZSBlc3NlbnRpYWxseSBleGFtaW5pbmcgdGhlIHJlc2lkdWFsIHdhdGVyLiBUaGlzIGNvdWxkIHJlcHJlc2VudCB0aGUgYW1vdW50IG9mIHdhdGVyIGF2YWlsYWJsZSB0byB0aGUgc3lzdGVtIGFmdGVyIGFjY291bnRpbmcgZm9yIHRoZSBkZW1hbmQgKFBFVCkgYW5kIHRoZSBvdXRmbG93IChkaXNjaGFyZ2UpLgoKYGBge3J9CiMgbWFrZSBsb25nIGZvcm0gd2l0aCBQRVRzdW0gYW5kIFBzdW0gYXMgdGhlIGtleS12YWx1ZSBwYWlycyAoZXhjbHVkZSB3dHJfeXIgZnJvbSApCmRhdF9zdW1fcGxvdCA8LSBpbmRhdGFfYW5hbHlzaXMgJT4lCiAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gICJrZXkiLCB2YWx1ZXNfdG8gPSAgInZhbHVlIiwgLXd0cl95cikKCiMgYmFyIHBsb3QgcGYgUEVUIGFuZCBQIGZvciBlYWNoIHllYXIKZ2dwbG90KGRhdF9zdW1fcGxvdCwgYWVzKHggPSB3dHJfeXIsIHkgPSB2YWx1ZSwgZmlsbCA9IGtleSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgbGFicyh4ID0gIldhdGVyIFllYXIiLCB5ID0gIm1tL3llYXIiLCBmaWxsID0ge30pCmBgYAoKYGBge3J9CiMjIyBUSU1JTkcKIyBjcmVhdGUgd2Vla2x5IG1lYW5zIG9yIHRvdGFscyBmb3IgYm90aCB0aW1lIHNlcmllcyBhbmQgcGxvdCB0aGVtIHRvZ2V0aGVyIHRvIGRldGVybWluZSB0aGUgdGltaW5nIG9mIGVhY2ggCmRhdF93ZWVrbHkgPC0gaW5kYXRhICU+JQogIGdyb3VwX2J5KFdlZWsgPSB3ZWVrKGRhdGUpKSAlPiUKICBzdW1tYXJpc2UoCiAgICBQRVQgPSBzdW0oUEVUX21tKSwgCiAgICBQID0gc3VtKHJ1bm9mZl9pbnB1dC5tbSkKICAgICkgJT4lCiAgICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAia2V5IiwgdmFsdWVzX3RvID0gInZhbHVlIiwgLVdlZWspCgojIGxpbmUgcGxvdCBvZiBQIGFuZCBQRVQgb24gYSB3ZWVrbHkgYmFzaXMuIFVzZSBkYXRfd2Vla2x5IGFzIHRoZSBkYXRhIHNvdXJjZS4KZ2dwbG90KGRhdF93ZWVrbHksIGFlcyh4ID0gV2VlaywgeSA9IHZhbHVlLCBjb2xvciA9IGtleSkpICsKICBnZW9tX2xpbmUoKSArICMgY3JlYXRlIGxpbmUgcGxvdAogIGxhYnMoeCA9ICJXZWVrIG9mIFllYXIiLCB5ID0gIm1tL3llYXIiLCBjb2xvciA9IHt9KQpgYGAKCiMgU2luZ2xlIG1vZGVsIHJ1bgpMb29rIGF0IHRoZSBwYXJhbWV0ZXJzIHRvIG1ha2Ugc3VyZSB5b3Uga25vdyB3aGF0IGVhY2ggcGFyYW1ldGVyIGRvZXMuIFRoZSB3YXkgdGhlIG1vZGVsIGlzIHNldCB1cCwgaXMgdGhhdCBldmVyeXRoaW5nIGlzIGhpZGRlbiBpbnNpZGUgYSBmdW5jdGlvbi4gVGhlIHVzZXIgKC0tPiB5b3UpIG9ubHkgZm9ybWF0cyB0aGUgaW5wdXQgZGF0YSBhbmQgcGFzc2VzIHRoZSBwYXJhbWV0ZXJzIHRvIHRoZSBmdW5jdGlvbi4gQWxsIG1vZGVsIG91dHB1dCBpcyBjb250YWluZWQgaW4gIm1vZGVsUnVuIi4gSWYgeW91IGxvb2sgYXQgdGhlIEVudmlyb25tZW50LCB5b3Ugd2lsbCBub3RpY2UgdGhhdCBtb2RlbFJ1biBpcyBhIGxpc3QuIEEgbGlzdCBpcyBldmVuIG1vcmUgZmxleGlibGUgaW4gdGVybXMgb2YgZGF0YSBzdG9yYWdlIHRoYW4gYSBkYXRhZnJhbWUgKGEgZGF0YWZyYW1lIGlzIGFjdHVhbGx5IGEgc3BlY2lhbCB0eXBlIG9mIGxpc3QuLi4pLiBXaGlsZSBsaXN0cyBhcmUgc3VwZXIgZmxleGlibGUsIHRoZXkgY2FuIGFsc28gYmUgbW9yZSBjdW1iZXJzb21lIHRvIGRlYWwgd2l0aC4gSSBpbmNsdWRlZCBzb21lIGNvZGUgdGhhdCB0YWtlcyB0aGUgb3V0cHV0IGZyb20gdGhlIG1vZGVsIHJ1biBhbmQgc2F2ZXMgYWxsIHRoZSBpbXBvcnRhbnQgYml0cyBhbmQgcGllY2VzIGluIGEgY29udmVuaWVudCBkYXRhZnJhbWUgY2FsbGVkIEhCVlJ1bi4gRm9yIHRoaXMgcGFydCAoc2luZ2xlIG1vZGVsIHJ1bnMpLCB5b3Ugd2lsbCByZWFsbHkgb25seSBuZWVkIHRoZSBkYXRhIGNvbnRhaW5lZCBpbiB0aGUgSEJWUnVuIGRhdGFmcmFtZS4KICAKIyBzaW5nbGUgbW9kZWwgZXhlY3V0aW9uCmBgYHtyfQojIHNldCB1cCB0aGUgcGFyYW1ldGVyIHZlY3Rvcgptb2RlbF9wYXJhbXMgPC0gYygKICAxLjA1LCAjIFNDRiBzbm93IGNvcnJlY3Rpb24gZmFjdG9yIFstXSAoZS5nLiwgMC45LTEuNSk7CiAgMS44MCwgIyBEREYgZGVncmVlIGRheSBmYWN0b3IgW21tL2RlZ0MvdGltZXN0ZXBdIChlLmcuLCAwLjAtNS4wIG1tL2RlZ0MvZGF5KTsKICAyLCAjIFRyIHRocmVzaG9sZCB0ZW1wZXJhdHVyZSBhYm92ZSB3aGljaCBwcmVjaXBpdGF0aW9uIGlzIHJhaW4gW2RlZ0NdIChlLmcuLCAxLjAtMy4wIGRlZ0MpOwogIDAsICMgVHMgdGhyZXNob2xkIHRlbXBlcmF0dXJlIGJlbG93IHdoaWNoIHByZWNpcGl0YXRpb24gaXMgc25vdyBbZGVnQ10gKGUuZy4sIC0zLjAtMS4wIGRlZ0MpOwogIC0wLjMzNiwgIyBUbSB0aHJlc2hvbGQgdGVtcGVyYXR1cmUgYWJvdmUgd2hpY2ggbWVsdCBzdGFydHMgW2RlZ0NdIChlLmcuLCAtMi4wLTIuMCBkZWdDKTsKICAwLjIsICMgTFByYXQgcGFyYW1ldGVyIHJlbGF0ZWQgdG8gdGhlIGxpbWl0IGZvciBwb3RlbnRpYWwgZXZhcG9yYXRpb24gWy1dIChlLmcuLCAwLjAtMS4wKTsKICAxMjEsICMgRkMgZmllbGQgY2FwYWNpdHksIGkuZS4sIG1heCBzb2lsIG1vaXN0dXJlIHN0b3JhZ2UgW21tXSAoZS5nLiwgMC02MDAgbW0pOwogIDIuNTIsICMgQkVUQSB0aGUgbm9uIGxpbmVhciBwYXJhbWV0ZXIgZm9yIHJ1bm9mZiBwcm9kdWN0aW9uIFstXSAoZS5nLiwgMC4wLTIwLjApOwogIDAuNDczLCAjIGswIHN0b3JhZ2UgY29lZmZpY2llbnQgZm9yIHZlcnkgZmFzdCByZXNwb25zZSBbdGltZXN0ZXBdIChlLmcuLCAwLjAtMi4wIGRheXMpOwogIDkuMDYsICMgazEgc3RvcmFnZSBjb2VmZmljaWVudCBmb3IgZmFzdCByZXNwb25zZSBbdGltZXN0ZXBdIChlLmcuLCAyLjAtMzAuMCBkYXlzKTsKICAxNDIsICMgazIgc3RvcmFnZSBjb2VmZmljaWVudCBmb3Igc2xvdyByZXNwb25zZSBbdGltZXN0ZXBdIChlLmcuLCAzMC4wLTI1MC4wIGRheXMpOwogIDUwLjEsICMgbHN1eiB0aHJlc2hvbGQgc3RvcmFnZSBzdGF0ZSwgaS5lLiwgdGhlIHZlcnkgZmFzdCByZXNwb25zZSBzdGFydCBpZiBleGNlZWRlZCBbbW1dIChlLmcuLCAxLjAtMTAwLjAgbW0pOwogIDIuMzgsICMgY3BlcmMgY29uc3RhbnQgcGVyY29sYXRpb24gcmF0ZSBbbW0vdGltZXN0ZXBdIChlLmcuLCAwLjAtOC4wIG1tL2RheSk7CiAgMTAsICMgYm1heCBtYXhpbXVtIGJhc2UgYXQgbG93IGZsb3dzIFt0aW1lc3RlcF0gKGUuZy4sIDAuMC0zMC4wIGRheXMpOwogIDI1ICMgY3JvdXRlIGZyZWUgc2NhbGluZyBwYXJhbWV0ZXIgW3RpbWVzdGVwXjIvbW1dIChlLmcuLCAwLjAtNTAuMCBkYXlzXjIvbW0pOwopCgoKIyBzZXQgdGltZSBwZXJpb2QKbW9kZWxfaW4gPC0gaW5kYXRhICU+JQogIGZpbHRlcihkYXRlID49IGFzX2RhdGUoIjIwMTctMTAtMDEiKSAmIGRhdGUgPD0gYXNfZGF0ZSgiMjAyMi0wOS0zMCIpKQoKIyBzZXQgdXAgdGhlIG1vZGVsCiMjIFRISVMgSVMgVEhFIEFDVFVBTCBNT0RFTCBFWEVDVVRJT04KbW9kZWxSdW4gPC0gVFVXbW9kZWwoCiAgcHJlYyA9IG1vZGVsX2luJHdlaWdodGVkX3ByZWNpcC5tbSwgIyBwcmVjaXAgaW5wdXQKICBhaXJ0ID0gbW9kZWxfaW4kVG1lYW5fYywgIyBhaXIgdGVtcCBpbnB1dAogIGVwID0gbW9kZWxfaW4kUEVUX21tLCAjIHBldCBpbnB1dAogIGFyZWEgPSAxLCAjIG9uZSB6b25lIGZvciB0aGUgZW50aXJlIHdhdGVyc2hlZAogIHBhcmFtID0gbW9kZWxfcGFyYW1zICMgaW5wdXQgbW9kZWwgcGFyYW1ldGVycwopCgoKIyBnZXQgYWxsIG91dHB1dHMgaW50byBhIG5pY2UgZGYKSEJWUnVuIDwtIHRpYmJsZSgKICBEYXRlID0gbW9kZWxfaW4kRGF0ZSwgIyBkYXRlCiAgUF9tbSA9IG1vZGVsUnVuJHByZWMsICMgcHJlY2lwCiAgVGFpciA9IG1vZGVsUnVuJGFpcnQsICMgYWlyIHRlbXAKICBTV0VvYnMgPSBtb2RlbF9pbiR3ZWlnaHRlZF9zd2UubW0sICMgb2JzZXJ2ZWQgc3dlCiAgUEVUID0gbW9kZWxSdW4kZXAsIyBwZXQKICBRb2JzID0gbW9kZWxfaW4kUV9tbV9kYXksICMgb2JzZXJ2ZWQgZGlzY2hhcmdlCiAgUXNpbSA9IG1vZGVsUnVuJHFbMSwgXSwgIyBzaW11bGF0ZWQgZGlzY2hhcmdlCiAgUXN1cmYgPSBtb2RlbFJ1biRxMFsxLCBdLCAjIHN1cmZhY2UgcnVub2ZmCiAgUXN1YnN1cmYgPSBtb2RlbFJ1biRxMVsxLCBdLCAjIHN1YnN1cmZhY2UgZmxvdwogIFFiYXNlID0gbW9kZWxSdW4kcTJbMSwgXSwgIyBncm91bmR3YXRlciBmbG93CiAgUmFpbiA9IG1vZGVsUnVuJHJhaW5bMSwgXSwgIyBzaW11bGF0ZWQgcmFpbgogIFNub3cgPSBtb2RlbFJ1biRzbm93WzEsIF0sICMgc2ltdWxhdGVkIHNub3dmYWxsCiAgTWVsdCA9IG1vZGVsUnVuJG1lbHRbMSwgXSwgIyBzaW11bGF0ZWQgbWVsdAogIFNXRXNpbSA9IG1vZGVsUnVuJHN3ZVsxLCBdLCAjIHNpbXVsYXRlZCBzd2UKICBTb2lsbW9pc3QgPSBtb2RlbFJ1biRtb2lzdFsxLCBdLCAjIHNpbXVsYXRlZCBzb2lsIHN0b3JhZ2UKICBBRVQgPSBtb2RlbFJ1biRldGFbMSwgXSwgIyBzaW11bGF0ZWQgZXZhcG90cmFuc3BpcmF0aW9uCiAgU3RvcmFnZVVwcGVyID0gbW9kZWxSdW4kc3V6WzEsIF0sICMgdXBwZXIgc3RvcmFnZSB2YWx1ZQogIFN0b3JhZ2VMb3dlciA9IG1vZGVsUnVuJHNselsxLCBdICMgbG93ZXIgc3RvcmFnZSB2YWx1ZQopCmBgYAoKIyMjICBPYmplY3RpdmUgZnVuY3Rpb25zCiMjIyMgS0dFCgpCZWZvcmUgd2UgY2FuIHN0YXJ0IHRyeWluZyB0byB0dW5lIG91ciBtb2RlbCB0byBsb29rIG1vcmUgbGlrZSB0aGUKb2JzZXJ2ZWQgZGlzY2hhcmdlIHJlY29yZCwgaXQgd291bGQgYmUgaGVscGZ1bCB0byBoYXZlIHNvbWUgc29ydCBvZgpxdWFudGlmaWVkIG1ldHJpYyBmb3IgaG93IHdlbGwgb3VyIG1vZGVsZWQgZGF0YSBmaXRzIHRoZSBtZWFzdXJlZCBkYXRhLgoKVGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IHdheXMgdG8gZG8gdGhpcywgYnV0IGRpc2N1c3Npb24gb2YgdGhlIHByb3MgYW5kIGNvbnMgb2YgdGhvc2UgYXBwcm9hY2hlcyBpcyBiZXlvbmQgdGhpcyBxdWljayBpbnRyb2R1Y3Rpb24gdG8gbW9kZWxpbmcuCgpIZXJlIHdlIHdpbGwgZGVtb25zdHJhdGUgdGhlIEtsaW5nLUd1cHRhIGVmZmljaWVuY3kgYm90aCBmb3IgcnVub2ZmIGFzIHdlbGwgYXMgZm9yIHN3ZS4KYGBge3J9CiMgc2VsZWN0IHRoZSBRb2JzIGFuZCBRc2ltIHRpbWVzZXJpZXMKIyBET04nVCBGT1JHRVQgVE8gRVhDTFVERSBUSEUgRklSU1QgWUVBUgpRb2JzIDwtIEhCVlJ1biRRb2JzWzM2NjpsZW5ndGgoSEJWUnVuJFFvYnMpXSAjIG9ic2VydmVkIHJ1bm9mZiBXSVRIT1VUIFdBUk0tVVAgUEVSSU9EClFzaW0gPC0gSEJWUnVuJFFzaW1bMzY2Omxlbmd0aChIQlZSdW4kUXNpbSldICMgc2ltdWxhdGVkIHJ1bm9mZiBXSVRIT1VUIFdBUk0tVVAgUEVSSU9ECgojIEtHRQprZ2Vfcl9xIDwtIGNvcihRb2JzLCBRc2ltKQprZ2VfYmV0YV9xIDwtIG1lYW4oUXNpbSkgLyBtZWFuKFFvYnMpCmtnZV9nYW1tYV9xIDwtIChzZChRc2ltKSAvIG1lYW4oUXNpbSkpIC8gKHNkKFFvYnMpIC8gbWVhbihRb2JzKSkKa2dlX3EgPC0gMSAtIHNxcnQoKGtnZV9yX3EgLSAxKV4yICsgKGtnZV9iZXRhX3EgLSAxKV4yICsgKGtnZV9nYW1tYV9xIC0gMSleMikKa2dlX3EKYGBgCgoKYGBge3J9CiMjIFNub3cgLSB3YXRlciBlcXVpdmFsZW50ClNXRW9icyA8LSBIQlZSdW4kU1dFb2JzWzM2NjpsZW5ndGgoSEJWUnVuJFNXRW9icyldICMgb2JzZXJ2ZWQgc3dlIFdJVEhPVVQgV0FSTS1VUCBQRVJJT0QKU1dFc2ltIDwtIEhCVlJ1biRTV0VzaW1bMzY2Omxlbmd0aChIQlZSdW4kU1dFb2JzKV0gIyBzaW11bGF0ZWQgc3dlIFdJVEhPVVQgV0FSTS1VUCBQRVJJT0QKCiMgS0dFCmtnZV9yX3N3ZSA8LSBjb3IoU1dFb2JzLCBTV0VzaW0pCmtnZV9iZXRhX3N3ZSA8LSBtZWFuKFNXRXNpbSkgLyBtZWFuKFNXRW9icykKa2dlX2dhbW1hX3N3ZSA8LSAoc2QoU1dFc2ltKSAvIG1lYW4oU1dFc2ltKSkgLyAoc2QoU1dFb2JzKSAvIG1lYW4oU1dFb2JzKSkKa2dlX3N3ZSA8LSAxIC0gc3FydCgoa2dlX3Jfc3dlIC0gMSleMiArIChrZ2VfYmV0YV9zd2UgLSAxKV4yICsgKGtnZV9nYW1tYV9zd2UgLSAxKV4yKQprZ2Vfc3dlCmBgYAoKIyMjIyBOU0UKTmFzaC1TdXRjbGlmZmUgRWZmaWNpZW5jeSAoTlNFKS4KCkJhc2ljYWxseSwgdGhlIE5TRSBsb29rcyBhdCBob3cgbXVjaCBiZXR0ZXIgeW91ciBtb2RlbCBydW4gZGlkIHRoYXQgaWYgeW91IGhhZCBqdXN0IHVzZWQgdGhlIG1lYW4gZGlzY2hhcmdlIGZvciB0aGUgZGF0YSByZWNvcmQgYXMgeW91cgoibW9kZWxsZWQgcmVzdWx0cyIuIEl0IGRvZXMgdGhpcyBieSBjb21wYXJpbmcgaG93IGZhciBvZmYgdGhlIG9ic2VydmVkIHZhbHVlcyB3aGVyZSBmcm9tIHRoZSBtZWFuIGRpc2NoYXJnZSB0byBob3cgZmFyIG9mZiB0aGUgbW9kZWxlZCB2YWx1ZXMgd2VyZSBmcm9tIHRoZSBvYnNlcnZlZCBkaXNjaGFyZ2UuCgpNYXRoZW1hdGljYWxseSwgTlNFIGlzIHRoZSBzdW0gb2YgdGhlIHNxdWFyZWQgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUKbW9kZWxlZCBhbmQgb2JzZXJ2ZWQgZGlzY2hhcmdlIGRpdmlkZWQgYnkgdGhlIHN1bSBvZiB0aGUgc3F1YXJlZApkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBvYnNlcnZlZCBhbmQgbWVhbiBkaXNjaGFyZ2UsIHN1YnRyYWN0ZWQgYnkgMS4KCiQkCk5TRSA9IDEgLSBcZnJhY3tcc3VtX3t0ID0gMX1ee1R9eyhRX21edCAtIFFfb150KV4yfX17XHN1bV97dCA9IDF9XntUfXsoUV9vXnQgLSBcYmFye1Ffb30pXjJ9fQokJCBXaGVyZSAkUV9tXnQkIGlzIG1vZGVsZWQgZGlzY2hhcmdlIGF0IHRpbWUgdCwgJFFfb150JCBpcyBvYnNlcnZlZApkaXNjaGFyZ2UgYXQgdGltZSB0LCBhbmQgJFxiYXJ7UV9vfSQgaXMgbWVhbiBvYnNlcnZlZCBkaXNjaGFyZ2UuCgpgYGB7cn0KI0NhbGN1bGF0ZSBOU0UgZm9yIHNub3csIFNXRSBpcyBtb2RlbGVkLCBTVEEyIGlzIG1lYXN1cmVkCk5TRV9RIDwtIDEgLSAoKHN1bSgoSEJWUnVuJFFvYnMgLSBIQlZSdW4kUXNpbSkgXiAyKSkgLyAKICAgICAgICAgICAgICAgICBzdW0oKEhCVlJ1biRRc2ltIC0gbWVhbihIQlZSdW4kUXNpbSkpIF4gMikpCgpOU0VfUQpgYGAKCmBgYHtyfQojQ2FsY3VsYXRlIE5TRSBmb3Igc25vdywgU1dFIGlzIG1vZGVsZWQsIFNUQTIgaXMgbWVhc3VyZWQKTlNFc25vIDwtIDEgLSAoKHN1bSgoSEJWUnVuJFNXRW9icyAtIEhCVlJ1biRTV0VzaW0pIF4gMikpIC8gCiAgICAgICAgICAgICAgICAgc3VtKChIQlZSdW4kU1dFc2ltIC0gbWVhbihIQlZSdW4kU1dFc2ltKSkgXiAyKSkKCk5TRXNubwpgYGAKIyMgQ2FsaWJyYXRlIEhCViBtYW51YWxseQoKV29vaG9vISBXZSBjYW4gbm93IHJ1biBvdXIgbW9kZWwgYW5kIGFzc2VzcyBob3cgd2VsbCBpdCBpcyB3b3JraW5nIQoKTm93LCBsZXQncyBzZWUgaG93IHdlbGwgd2UgY2FuIGdldCBpdCB0byB3b3JrLiBUaGUgY29kZSBiZWxvdyBydW5zIHRoZSBtb2RlbCwgcHJvZHVjZXMgYSBwbG90LCBhbmQgY2FsY3VsYXRlcyB0aGUgTlNFIGJhc2VkIG9uIGRpc2NoYXJnZS4KCmBgYHtyfQoKIyBzZXQgdXAgdGhlIHBhcmFtZXRlciB2ZWN0b3IKbW9kZWxfcGFyYW1zIDwtIGMoCiAgMS4wNSwgIyBTQ0Ygc25vdyBjb3JyZWN0aW9uIGZhY3RvciBbLV0gKGUuZy4sIDAuOS0xLjUpOwogIDEuODAsICMgRERGIGRlZ3JlZSBkYXkgZmFjdG9yIFttbS9kZWdDL3RpbWVzdGVwXSAoZS5nLiwgMC4wLTUuMCBtbS9kZWdDL2RheSk7CiAgMiwgIyBUciB0aHJlc2hvbGQgdGVtcGVyYXR1cmUgYWJvdmUgd2hpY2ggcHJlY2lwaXRhdGlvbiBpcyByYWluIFtkZWdDXSAoZS5nLiwgMS4wLTMuMCBkZWdDKTsKICAwLCAjIFRzIHRocmVzaG9sZCB0ZW1wZXJhdHVyZSBiZWxvdyB3aGljaCBwcmVjaXBpdGF0aW9uIGlzIHNub3cgW2RlZ0NdIChlLmcuLCAtMy4wLTEuMCBkZWdDKTsKICAtMC4zMzYsICMgVG0gdGhyZXNob2xkIHRlbXBlcmF0dXJlIGFib3ZlIHdoaWNoIG1lbHQgc3RhcnRzIFtkZWdDXSAoZS5nLiwgLTIuMC0yLjAgZGVnQyk7CiAgMC4yLCAjIExQcmF0IHBhcmFtZXRlciByZWxhdGVkIHRvIHRoZSBsaW1pdCBmb3IgcG90ZW50aWFsIGV2YXBvcmF0aW9uIFstXSAoZS5nLiwgMC4wLTEuMCk7CiAgMTIxLCAjIEZDIGZpZWxkIGNhcGFjaXR5LCBpLmUuLCBtYXggc29pbCBtb2lzdHVyZSBzdG9yYWdlIFttbV0gKGUuZy4sIDAtNjAwIG1tKTsKICAyLjUyLCAjIEJFVEEgdGhlIG5vbiBsaW5lYXIgcGFyYW1ldGVyIGZvciBydW5vZmYgcHJvZHVjdGlvbiBbLV0gKGUuZy4sIDAuMC0yMC4wKTsKICAwLjQ3MywgIyBrMCBzdG9yYWdlIGNvZWZmaWNpZW50IGZvciB2ZXJ5IGZhc3QgcmVzcG9uc2UgW3RpbWVzdGVwXSAoZS5nLiwgMC4wLTIuMCBkYXlzKTsKICA5LjA2LCAjIGsxIHN0b3JhZ2UgY29lZmZpY2llbnQgZm9yIGZhc3QgcmVzcG9uc2UgW3RpbWVzdGVwXSAoZS5nLiwgMi4wLTMwLjAgZGF5cyk7CiAgMTQyLCAjIGsyIHN0b3JhZ2UgY29lZmZpY2llbnQgZm9yIHNsb3cgcmVzcG9uc2UgW3RpbWVzdGVwXSAoZS5nLiwgMzAuMC0yNTAuMCBkYXlzKTsKICA1MC4xLCAjIGxzdXogdGhyZXNob2xkIHN0b3JhZ2Ugc3RhdGUsIGkuZS4sIHRoZSB2ZXJ5IGZhc3QgcmVzcG9uc2Ugc3RhcnQgaWYgZXhjZWVkZWQgW21tXSAoZS5nLiwgMS4wLTEwMC4wIG1tKTsKICAyLjM4LCAjIGNwZXJjIGNvbnN0YW50IHBlcmNvbGF0aW9uIHJhdGUgW21tL3RpbWVzdGVwXSAoZS5nLiwgMC4wLTguMCBtbS9kYXkpOwogIDEwLCAjIGJtYXggbWF4aW11bSBiYXNlIGF0IGxvdyBmbG93cyBbdGltZXN0ZXBdIChlLmcuLCAwLjAtMzAuMCBkYXlzKTsKICAyNSAjIGNyb3V0ZSBmcmVlIHNjYWxpbmcgcGFyYW1ldGVyIFt0aW1lc3RlcF4yL21tXSAoZS5nLiwgMC4wLTUwLjAgZGF5c14yL21tKTsKKQoKCiMgc2V0IHRpbWUgcGVyaW9kCm1vZGVsX2luIDwtIGluZGF0YSAlPiUKICBmaWx0ZXIoZGF0ZSA+PSBhc19kYXRlKCIyMDE3LTEwLTAxIikgJiBkYXRlIDw9IGFzX2RhdGUoIjIwMjItMDktMzAiKSkKCiMgc2V0IHVwIHRoZSBtb2RlbAojIyBUSElTIElTIFRIRSBBQ1RVQUwgTU9ERUwgRVhFQ1VUSU9OCm1vZGVsUnVuIDwtIFRVV21vZGVsKAogIHByZWMgPSBtb2RlbF9pbiR3ZWlnaHRlZF9wcmVjaXAubW0sICMgcHJlY2lwIGlucHV0CiAgYWlydCA9IG1vZGVsX2luJFRtZWFuX2MsICMgYWlyIHRlbXAgaW5wdXQKICBlcCA9IG1vZGVsX2luJFBFVF9tbSwgIyBwZXQgaW5wdXQKICBhcmVhID0gMSwgIyBvbmUgem9uZSBmb3IgdGhlIGVudGlyZSB3YXRlcnNoZWQKICBwYXJhbSA9IG1vZGVsX3BhcmFtcyAjIGlucHV0IG1vZGVsIHBhcmFtZXRlcnMKKQoKCiMgZ2V0IGFsbCBvdXRwdXRzIGludG8gYSBuaWNlIGRmCkhCVlJ1biA8LSB0aWJibGUoCiAgRGF0ZSA9IG1vZGVsX2luJERhdGUsICMgZGF0ZQogIFBfbW0gPSBtb2RlbFJ1biRwcmVjLCAjIHByZWNpcAogIFRhaXIgPSBtb2RlbFJ1biRhaXJ0LCAjIGFpciB0ZW1wCiAgU1dFb2JzID0gbW9kZWxfaW4kd2VpZ2h0ZWRfc3dlLm1tLCAjIG9ic2VydmVkIHN3ZQogIFBFVCA9IG1vZGVsUnVuJGVwLCMgcGV0CiAgUW9icyA9IG1vZGVsX2luJFFfbW1fZGF5LCAjIG9ic2VydmVkIGRpc2NoYXJnZQogIFFzaW0gPSBtb2RlbFJ1biRxWzEsIF0sICMgc2ltdWxhdGVkIGRpc2NoYXJnZQogIFFzdXJmID0gbW9kZWxSdW4kcTBbMSwgXSwgIyBzdXJmYWNlIHJ1bm9mZgogIFFzdWJzdXJmID0gbW9kZWxSdW4kcTFbMSwgXSwgIyBzdWJzdXJmYWNlIGZsb3cKICBRYmFzZSA9IG1vZGVsUnVuJHEyWzEsIF0sICMgZ3JvdW5kd2F0ZXIgZmxvdwogIFJhaW4gPSBtb2RlbFJ1biRyYWluWzEsIF0sICMgc2ltdWxhdGVkIHJhaW4KICBTbm93ID0gbW9kZWxSdW4kc25vd1sxLCBdLCAjIHNpbXVsYXRlZCBzbm93ZmFsbAogIE1lbHQgPSBtb2RlbFJ1biRtZWx0WzEsIF0sICMgc2ltdWxhdGVkIG1lbHQKICBTV0VzaW0gPSBtb2RlbFJ1biRzd2VbMSwgXSwgIyBzaW11bGF0ZWQgc3dlCiAgU29pbG1vaXN0ID0gbW9kZWxSdW4kbW9pc3RbMSwgXSwgIyBzaW11bGF0ZWQgc29pbCBzdG9yYWdlCiAgQUVUID0gbW9kZWxSdW4kZXRhWzEsIF0sICMgc2ltdWxhdGVkIGV2YXBvdHJhbnNwaXJhdGlvbgogIFN0b3JhZ2VVcHBlciA9IG1vZGVsUnVuJHN1elsxLCBdLCAjIHVwcGVyIHN0b3JhZ2UgdmFsdWUKICBTdG9yYWdlTG93ZXIgPSBtb2RlbFJ1biRzbHpbMSwgXSAjIGxvd2VyIHN0b3JhZ2UgdmFsdWUKKQoKI1RyaW0gb3V0IHRoZSB3YXJtIHVwIHBlcmlvZApPdXRUcmltIDwtIEhCVlJ1biAlPiUgc2xpY2UoMzY2Om4oKSkKCiNDYWxjdWxhdGUgTlNFCk5TRSA8LSAxIC0gKChzdW0oKE91dFRyaW0kUXNpbSAtIE91dFRyaW0kUW9icykgXiAyKSkgLyAKICAgICAgICAgICAgICAgICBzdW0oKE91dFRyaW0kUW9icyAtIG1lYW4oT3V0VHJpbSRRb2JzKSkgXiAyKSkKCnByaW50KE5TRSkKYGBgCgojIyBQbG90IG9ic2VydmVkIGFuZCBtb2RlbCBzaW11bGF0aW9ucwoKR2VuZXJhdGUgcGxvdHMgdGhhdCBpbmNsdWRlIGFuZCBjb21wYXJlIHRoZSBkaWZmZXJlbnQgbW9kZWxlZCBmbHV4ZXMgZnJvbSB5b3VyIGJlc3QgTlNFLiBTb21lIG9mIHRob3NlIGZsdXhlcyBjYW4gYmUgaW1tZWRpYXRlbHkgY29tcGFyZWQgdG8gb2JzZXJ2ZWQgZGF0YSAoZS5nLiwgcnVub2ZmIG9yIFNXRSksIHdoaWxlIG90aGVycyBvbmx5IGV4aXN0IGluIHNpbXVsYXRlZCBmb3JtIChlLmcuLCBzdG9yYWdlcyBvciBvdXRmbG93cyBvZiB0aGUgdmFyaW91cyBydW5vZmYgY29tcG9uZW50cykgYW5kIG5lZWQgdG8gYmUgYXNzZXNzZWQgd2l0aCB0aGUgcGVyY2VwdHVhbCBtb2RlbCBpbiBtaW5kLiAgCk1ha2Ugc3VyZSB0aGF0IHRoZSBheGVzIGFyZSBwcm9wZXJseSBsYWJlbGVkIHdoZW4geW91IGNyZWF0ZSBwbG90cy4gVGhlIHNjcmlwdCBiZWxvdyB3aWxsIGdldCB5b3Ugc3RhcnRlZC4gCgpgYGB7cn0KIyBBZGQgZGF0ZSB0byB0aGUgSEJWUnVuIHJlc3VsdCB0aWJibGUKSEJWUnVuIDwtIGFzLmRhdGEuZnJhbWUoSEJWUnVuKQpIQlZSdW4kRGF0ZSA8LSBtb2RlbF9pbiRkYXRlCnN0cihIQlZSdW4pCgojIFJvdW5kIHRoZSBOU0UgZm9yIGRpc3BsYXkKbnNlX2xhYmVsIDwtIHBhc3RlKCJOU0UgPSIsIHJvdW5kKE5TRSwgMykpCgpxX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBIQlZSdW4pICsKICBnZW9tX2xpbmUoYWVzKHggPSBEYXRlLCB5ID0gUW9icywgY29sb3IgPSAiUW9icyIpKSArICAjIFFvYnMKICBnZW9tX2xpbmUoYWVzKHggPSBEYXRlLCB5ID0gUXNpbSwgY29sb3IgPSAiUXNpbSIpKSArICAjIFFzaW0KICBhbm5vdGF0ZSgidGV4dCIsCiAgICAgICAgICAgeCA9IG1heChIQlZSdW4kRGF0ZSkgLSAxMDAsICAjIE1vdmUgbGFiZWwgIyBkYXlzIGZyb20gdGhlIGVuZAogICAgICAgICAgIHkgPSBtYXgoSEJWUnVuJFFvYnMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgbGFiZWwgPSBuc2VfbGFiZWwsCiAgICAgICAgICAgaGp1c3QgPSAxLCB2anVzdCA9IDEuNSwgc2l6ZSA9IDUsIGZvbnRmYWNlID0gImJvbGQiKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9ICJRIChtbS9kYXkpIiwgY29sb3IgPSBOVUxMLCB0aXRsZSA9ICJRb2JzIGFuZCBRc2ltIikKCgojIE1ha2UgaXQgaW50ZXJhY3RpdmUgd2l0aCBwbG90bHkKZ2dwbG90bHkocV9wbG90KQoKYGBgCgojIyMgTW9yZSBwbG90cwoKYGBge3J9CiMgU3dlCnN3ZV9wbG90IDwtIGdncGxvdChkYXRhID0gSEJWUnVuKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gRGF0ZSwgeSA9IFNXRW9icywgY29sb3IgPSAiU1dFb2JzIikpICsgIyBTV0VvYnMKICBnZW9tX2xpbmUoYWVzKEJMQU5LKSkgKyAjIFNXRXNpbQogIGxhYnMoeCA9IHt9LCB5ID0gIlNXRSAobW0pIiwgY29sb3IgPSB7fSkKZ2dwbG90bHkoc3dlX3Bsb3QpCmBgYAoKCmBgYHtyfQojIFEwLCBRMSwgUTIKcV9idWNrZXRfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IEhCVlJ1bikgKwogIGdlb21fbGluZShhZXMoeCA9IERhdGUsIHkgPSBRc3VyZiwgY29sb3IgPSAiUXN1cmYiKSkgKyAjIFFzdXJmCiAgZ2VvbV9saW5lKGFlcyh4ID0gRGF0ZSwgeSA9IFFzdWJzdXJmLCBjb2xvciA9ICJRc3Vic3VyZiIpKSArICNRc3Vic3VyZgogIGdlb21fbGluZShhZXMoeCA9IERhdGUsIHkgPSBRYmFzZSwgY29sb3IgPSAiUWJhc2UiKSkgKyAjIFFiYXNlCiAgbGFicyh4ID0ge30sIHkgPSAiUSAobW0pIiwgY29sb3IgPSB7fSwgdGl0bGUgPSAiUTAsIFExLCBhbmQgUTIiKQpnZ3Bsb3RseShxX2J1Y2tldF9wbG90KQpgYGA=